概念
JAVA动态代理主要用来做方法的增强,在源码不动的情况下,对一些方法实现相应的增强及扩展,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话,比如可以添加调用日志,做事务控制等。
动态代理形式
实现动态代理的形式有:JDK动态代理,Cglib代理,Javassist 实现动态代理,ASM实现动态代理等。
详情请参考以下介绍。
创建JDK动态代理
JDK动态代理对象
1)接口代理; 代理对象不需要实现接口,但是目标对象一定要实现接口;否则不能用动态代理!
2)代理对象的生成,是利用JDKAPI, 动态的在内存中构建代理对象(需要我们指定创建 代理对象/目标对象 实现的接口的类型);
代码实现
public class UserDaoDynamicProxy {
//维护一个目标对象
private Object targetObject;
public UserDaoDynamicProxy(Object target){
this.targetObject = target;
}
public Object getProxyInstance(){
return Proxy.newProxyInstance(
targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("动态代理,在开始方法前执行操作");
//执行目标对象方法
Object returnValue = method.invoke(targetObject, args);
System.out.println("动态代理,在开始方法后执行操作");
return returnValue;
}
});
}
}
Cglib代理
JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。 Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。
1 ) 需要引入cglib – jar文件, 但是spring的核心包中已经包括了cglib功能,所以直接引入spring-core-3.2.5.jar即可;
2)引入功能包后,就可以在内存中动态构建子类
3)代理的类不能为final, 否则报错。
4) 目标对象的方法如果为final/static, 那么就不会被拦截,即不会执行目标对象额外的业务方法
代码参考
public class UserDaoCglibProxy implements MethodInterceptor{
//维护目标对象
private Object targetObject;
public UserDaoCglibProxy(Object target){
this.targetObject = target;
}
//给目标对象创建代理对象
public Object getProxyInstance(){
//工具类
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(targetObject.getClass());
//设置回调函数
enhancer.setCallback(this);
//创建子类
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy arg3) throws Throwable {
System.out.println("我是CGLIB代理对象,在开始方法前执行操作");
Object return = method.invoke(targetObject, args);
System.out.println("我是CGLIB代理对象,在开始方法后执行操作");
return return;
}
}
测试类
public class App {
public static void main(String[] args) {
// TODO Auto-generated method stub
IUserDao userDao = new UserDao();
IUserDao userDao2 = (IUserDao) new UserDaoDynamicProxy(userDao).getProxyInstance();
userDao2.save();
System.out.println("\n------------------------\n");
IUserDao userDao3 = (IUserDao) new UserDaoCglibProxy(userDao).getProxyInstance();
userDao3.save();
}
}
总结 :
在Spring的AOP编程中,
如果加入容器的目标对象有实现接口,用JDK代理;
如果目标对象没有实现接口,用Cglib代理;
Javassist 实现动态代理
javassist 是一款非常优秀的Java 字节码引擎工具,能够在运行时编译、生成Java Class,且可以进行类判断过滤,实现动态代理。
maven依赖
<dependency>
<groupId>org.javassist</groupId>
<artifactId>javassist</artifactId>
<version>3.21.0-GA</version>
</dependency>
通过javassist.util.proxy.ProxyFactory类来生成代理:
public Object getProxy(Class<?> type) throws IllegalAccessException, InstantiationException {
ProxyFactory f = new ProxyFactory();
f.setSuperclass(type);
f.setFilter(new MethodFilter() {
public boolean isHandled(Method m) {
// ignore finalize()
return !m.getName().equals("finalize");
}
});
Class c = f.createClass();
MethodHandler mmi= new MethodHandler() {
public Object invoke(Object self, Method m, Method proceed,
Object[] args) throws Throwable {
System.out.println("method name: " + m.getName()+" exec");
return proceed.invoke(self, args); // execute the original method.
}
};
Object proxy = c.newInstance();
((Proxy)proxy).setHandler(mmi);
return proxy;
}
ASM实现动态代理
待续!!!.
@Author:zhangjialian