Java动态代理机制详解
标签(空格分隔): 动态代理 cglib jdk
动态代理
使用场景
可以在运行的时候才切入改变类的方法,而不需要预先定义它。通过动态代理,我们可以实现类的增强,可以像AOP那样在方法执行之前,或者之后,执行安全、日志等操作
。
例如依赖注入的@Bean、@Autowired,事务注解@Transactional等都有用到,换言之就是Srping的AOP(切面编程)。
JDK动态代理
基于接口代理,凡是类的方法非public修饰,或者用了static关键字修饰,那这些方法都不能被Spring AOP增强
原理
在获取到代理类的classLoader及相应的接口之后,可以获取到代理类的Class对象,通过反射获取到构造方法,new一个对象绑定到InvocationHandler上。
#Proxy类
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces, InvocationHandler h)
- loder,选用的类加载器。一般都会用加载代理对象的类加载器。
- interfaces,被代理的类所实现的接口,这个接口可以是多个。
- h,绑定代理类的一个方法。
loader跟interfaces基本决定了这个代理类的所属对象
InvocationHandler在调用代理类的方法时会执行一个绑定的方法,同时会替代原本方法的结果返回。
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//会导致死循环
method.invoke(proxy, args)
//object为被代理的对象
method.invoke(object,args)
}
proxy是代理对象,当该对象的方法被调用时,会触发InvocationHandler中的invoke方法。
例子
public interface Person {
public void say();
}
public class Men implements Person {
@Override
public void say() {
System.out.println("hello, i am a man");
}
}
Men man = new Men();
Person person = (Person) Proxy.newProxyInstance(
man.getClass().getClassLoader(),
man.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before say method begin");
method.invoke(man,args);
System.out.println("after say method finish");
return null;
}
});
person.say();
结果
before say method begin
hello, i am a man
after say method finish
Cglib动态代理
基于子类代理,凡是类的方法使用了private、static、final修饰,那这些方法都不能被Spring AOP增强
JDK动态代理,发现其真实对象必须提供接口才可以使用。在一些不提供接口的环境中,只能采用一些别的第三方技术,比如CGLIB动态代理。
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
public class CglibProxyExample implements MethodInterceptor {
public Object getProxy(Class clz){
//CGLIB enhancer增强类对象
Enhancer enhancer = new Enhancer();
//设置增强类型
enhancer.setSuperclass(clz);
//定义代理对象为当前对象,要求当前对象实现MethodInterceptor方法
enhancer.setCallback(this);
return enhancer.create();
}
@Override
/**
* @param proxy 代理对象
* @param method 方法
* @param args 方法参数
* @param methodProxy 方法代理
* @return 代理逻辑返回
* @throws Throwable 抛出异常
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("before say method begin");
Object retObj = methodProxy.invokeSuper(proxy,args);
System.out.println("after say method finish");
return retObj;
}
}
CglibProxyExample cglibProxyExample = new CglibProxyExample();
Men men = (Men)cglibProxyExample.getProxy(Men.class);
men.say();