代理与动态代理的概念
代理关系示图:
代理关系类图:
注:由上图可见,代理对象与代理类之间是实现了同接口的不同类,互相之间不存在继承关系而是组合关系(亦可以理解为类图中的“委托”)。至于代理与动态代理的区别,可以简单理解为代理类的生成方式不同而已。
静态代理:代理类由手动编码生成,缺点是不够灵活。
动态代理:可以采用Jdk提供Proxy.newPorxyInstance(…)运行时动态生产(一些基于接口的三方组件就是这种方式,例如:mybatis、feigen等)。
Proxy与CGLib的区别
JdkProxy的使用:
public class ProxyTest {
@Test
public void test1() {
JdkTestA jdkTestA = new JdkTestA();
IJdkTest jdkTest = (IJdkTest) Proxy.newProxyInstance(jdkTestA.getClass().getClassLoader(), JdkTestA.class.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(jdkTestA, args);
}
});
System.out.println(jdkTest.getClass().getName());
System.out.println(jdkTest.greeting());
}
}
CGLib的使用(原理此处暂时略过,涉及到字节码修改的东西):
public class MyProxyTestA {
public void greeting() {
System.out.println("my cglib greeting !!!");
}
}
public class CglibTest {
@Test
public void test1() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(MyProxyTestA.class);
enhancer.setNamingPolicy(new DefaultNamingPolicy() {
@Override
protected String getTag() {
return "ByZanghCGLIB";
}
});
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
System.out.println("before,is inherit=" + (obj instanceof MyProxyTestA));
Object res = methodProxy.invokeSuper(obj, args);
System.out.println("after");
return res;
}
});
MyProxyTestA testAWithCglib = (MyProxyTestA) enhancer.create();
System.out.println(testAWithCglib.getClass().getName() + ",id=");
testAWithCglib.greeting();
}
}
输出结果
org.thinking.spring.proxy.cglib.MyProxyTestA$$EnhancerByZanghCGLIB$$c0dbde28,id=
before,is inherit=true
my cglib greeting !!!
after
注1:由日志中inherit=true可见CGLib生成的代理类和代理对象是存在继承关系的。其实也由类名Enhancer(增强器)而非Proxy可以推测CGLib是通过继承后,重写方法实现对目标方法的控制的。严格来讲CGLib不能叫代理,这也是他和JdkProxy本质上的区别。
注2:因为是继承方式则CGLib不需要像JdkProxy那样需要代理目标存在接口。使用限制更少,在Spring中通常作为JdkProxy的备选方案(JdkProxy的效率随着jdk版本迭代性能越来越好)。