JDK动态代理机制

标签: jdk 代理 | 发表时间:2013-10-11 00:39 | 作者:xtayfjpk
出处:http://blog.csdn.net

    代理模式有两种,一种是静态代理,这种方式需要为每一个被代理类写一个代理类,显示比较麻烦。还一种是动态代理,动态代理实现方式一般有两种,JDK动态代理与CGLIB动态代理,这里说一下对JDK动态代理的理解。

    JDK动态代理最核心的就类就是java.lang.reflect.Proxy,可调用Proxy.newInstance(..)生成动态代理。

如果有一个UserService接口(JDK动态代理必须有接口),一个UserService接口实现类UserServiceBean,现在要生成一个UserServiceBean的动态代理类代码如下:

final UserService userService = new UserServiceBean();
Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserService.class}, new InvocationHandler() {
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		Object obj = method.invoke(userService, args);
		return obj;
	}
});
UserService us = (UserService) proxy;
newInstance方法的第一个参数指定一个ClassLoader(类装载器),第二个参数是一个接口数组,生成的代理类会实现数组中的所有接口,第三个参数为一个InvocationHandler对象,InvocationHandler是一个接口,所以这里用了匿名内部实现值。


    一个动态类在运行时被创建,并在创建的时候实现了一系统接口,就是在接口数组中指定的接口。一个代理接口是被代理类实现的接口。一个代理实例是代理类实例,每一个代理实现都关联了一个InvocationHandler对象,该对象实现了InvocationHandler接口,当通过代理接口调用一个代理实例的一个方法时会被转发到该代理实例关系的InvocationHandler对象的invoke方法,一个java.lang.reflect.Method对象表示了被调用的方法,而Object[]包含了该方法的参数,把invoke的返回值为作代理对象方法的返回值。


   一个代理类有如下属性:

@@ 一个代理是public,final(即不能被继承),非abstract的

@@ 该代理类的名称为"$Proxyn",其中n为一个数字

@@ 所有的代理类都继承自java.lang.reflect.Proxy

@@ 当一个代理类创建的时候,按照在接口数组中写的顺序实现了所有接口

@@ 如果一个代理类实现了一个非public接口,那么该代理类被定义在与该非public接口相同的包中,因为一个非public接口    不可能是private与protected,那么就只是能default的,即不加任何访问修饰符的,而这种只有在同一个包中的类才能    访问,这就决定了该代理类也必须位于该包中。如果代理类实现的是一public接口,这个代理类的包没有具体指定就是在缺省    包中,即没有包名。

@@ Proxy.isProxyClass方法用于判断一个是不是一个动态代理类

@@ 每一个代理类都有一个带一个参数的公开构造方法,该参数是一个实现了InvocationHandler接口的对象,把该对象关联到    一个代理实例上。

    当调用代理实例的从Object类继承而来的hashCode,equals,toString方法时,也会转发到InvocationHandler的invoke方法,就像接口中声明的方法一样。而其它从Object类继承而来的public方法是不会被代理实现覆盖的,如:getClass等,其实这些方法也不可能被覆盖,因为这些方法都是final的。


下面举一个JDK动态代理应用例子。

在项目中如果使用了Spring的话,事务都是交由Spring来管理的,但是如果有些项目没有使用Spring的话,这时事务的自动开启,提交,回滚操作就可以用JDK动态代理实现,假DAO用的是Hibernate

package cn.it.shopping.service.system.impl;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.hibernate.Session;

import cn.it.shopping.misc.SessionFactoryHelper;
import cn.it.shopping.pojo.system.Admin;
import cn.it.shopping.service.base.DaoSupport;
import cn.it.shopping.service.system.AdminService;
import cn.it.shopping.utils.MD5;

/**
 * 自己实现的动态代理AdminServiceBean,在方法开始前打开事务,在方法执行打开事务,提交或回滚后关闭session
 * 出现异常自动回滚
 * @author zj
 *
 */
public class ProxyAdminServiceBean extends DaoSupport<Admin> implements AdminService {
	private static ProxyAdminServiceBean instance = new ProxyAdminServiceBean();
	private ProxyAdminServiceBean(){} //保证单例
	
	/**
	 * 真正返回的是instance的一个代理对象
	 */
	public static AdminService getInstance() {
		return (AdminService) Proxy.newProxyInstance(instance.getClass().getClassLoader(), new Class[]{AdminService.class}, new InvocationHandler() {
			
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
				//SessionFactoryHelper为获取SessionFactory的一个工具类
				//这样获取的Session会在事务提交或回滚时自动提交,因为返回的本身就已经是个代理对象
				Session session = SessionFactoryHelper.getSessionFactory().getCurrentSession();
				session.getTransaction().begin();//开始前开启事务
				Object result;
				try {
					result = method.invoke(instance, args);//执行业务逻辑
					session.getTransaction().commit();//业务逻辑执行完成后提交事务
					return result;
				} catch (Exception e) {
					session.getTransaction().rollback(); //如果业务逻辑出现例外则事务回滚
					throw new RuntimeException(e);
				} finally {
					if(null!=session && session.isOpen()) {
						session.close();//这里是不会执行的,因为Session会在事务提交或回滚时自动提交,如果调用的是openSession获取Session这里就会执行
					}
				}
			}
		});
	}

	public void save(Admin entity) {
		String pass = MD5.MD5Encode(entity.getPass());
		entity.setPass(pass);
		super.save(entity);
	}
}



作者:xtayfjpk 发表于2013-10-10 16:39:06 原文链接
阅读:41 评论:0 查看评论

相关 [jdk 代理] 推荐:

JDK动态代理机制

- - CSDN博客编程语言推荐文章
    代理模式有两种,一种是静态代理,这种方式需要为每一个被代理类写一个代理类,显示比较麻烦. 还一种是动态代理,动态代理实现方式一般有两种,JDK动态代理与CGLIB动态代理,这里说一下对JDK动态代理的理解.     JDK动态代理最核心的就类就是java.lang.reflect.Proxy,可调用Proxy.newInstance(..)生成动态代理.

JAVA之JDK动态代理

- - Java - 编程语言 - ITeye博客
在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过这个类和接口,可以生成JDK动态代理类或动态代理对象. Proxy提供了用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类,如果在程序中为一个或多个接口动态的生成实现类,就可以使用Proxy来创建动态代理类,.

Spring AOP 代理机制 JDK&CGLIB

- - 开源软件 - ITeye博客
Spring AOP使用JDK动态代理或者CGLIB来为目标对象创建代理. (建议优先使用JDK的动态代理). 如果被代理的目标对象实现了至少一个接口,则会使用JDK动态代理. 所有该目标类型实现的接口都将被代理. 若该目标对象没有实现任何接口,则创建一个CGLIB代理. 如果你希望强制使用CGLIB代理,(例如:希望代理目标对象的所有方法,而不只是实现自接口的方法) 那也可以.

动态代理双剑客--JDK Proxy与CGLIB

- - CSDN博客推荐文章
研究过设计模式的同胞们都知道代理模式可以有两种实现方案:. 1.接口实现(或继承抽象类). 都可以通过Proxy控制对Target的访问. “接口实现”的方式更加灵活,代理类可以代理所有实现了ISubject接口的类;. “继承父类”的方式代理类只能代理它的父类,因为java中只支持单继承. 如果Target有直接接口,那么这两种方式都可以;.

实现动态代理的两种方式介绍+例子demo(JDK、CGlib)

- - CSDN博客架构设计推荐文章
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢. CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑. JDK动态代理与CGLib动态代理均是实现Spring AOP的基础.

Sun JDK 1.6内存管理

- 小丑鱼 - 淘宝JAVA中间件团队博客
分为使用篇、调优篇和实现篇三个部分,使用篇为填鸭式,调优篇为pattern式,实现篇为启发式,三个PPT的目标为:. 1.掌握Sun JDK的内存区域的划分;. 2.掌握Sun JDK垃圾收集器的使用方法和触发时机;. 4.掌握一些基本的GC调优的方法;. 5.了解自动内存管理的常见实现方法,以及Sun JDK所做的优化.

JDK自带监控工具

- - ITeye博客
         系统在生产运行过程中最重要的工作莫过于监控与问题的处理,监控是预防问题产生很重要的手段. 在监控过程中可以发现那些模块或进程出现了问题,出现问题后会及时通知问题负责人.         实现监控的手段非常多,有系统级别监控系统,也有监控小工具等等. Java 就已经自带了一些监控工具,可以不借助外部软件的情况下简单、快速查看相应监控信息.

赵雅智_Java JDK 5.0 内省

- - CSDN博客推荐文章
开发框架时,经常需要使用java对象的属性来封装程序的数据,每次都使用反射技术完成此类操作过于麻烦. 所以sun公司开发了一套API,专门用于操作java对象的属性. 什么是Java对象的属性和属性的读写方法?. 内省访问JavaBean属性的两种方式:. 通过PropertyDescriptor类操作Bean的属性.

Hadoop 2.7.0 发布,不再支持 JDK 6

- - 开源中国社区最新新闻
Apache Hadoop 2.7.0 发布,包括大量显著改进,值得关注的改进如下:. 此版本不再支持 JDK 6 运行时,仅支持 JDK 7+. 还有一些重要的问题需要通过测试,用于生产环境的用户请等待 2.7.1/2.7.2. 支持 Windows Azure 存储 —— Blob. 自动分享,全局缓存 YARN 本地化资源(测试阶段).

常用的JDK自带命令行工具

- - 四火的唠叨
文章系本人原创,转载请保持完整性并注明出自 《四火的唠叨》. 在 这里可以找得到这些工具的列表,虽然官网上免责声明为 “The tools described in this section are unsupported and experimental in nature and should be used with that in mind.