一、JDK动态代理案例
1)、使用步骤
- 新建一个接口
- 为接口创建一个实现类
- 创建代理类实现java.lang.reflect.InvocationHandler接口
- 测试
2)、代码实现
public interface Say {
void say(String words);
}
public class SayImpl implements Say {
@Override
public void say(String words) {
System.out.println("hello:" + words);
}
}
public class JDKProxy implements InvocationHandler{
private Object target;
public JDKProxy(Object obejct) {
this.target = obejct;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("-----begin-----");
Object obj = method.invoke(target,args);
System.out.println("-----end-----");
return obj;
}
}
public class JDKProxyTest {
public static void main(String[] args) {
JDKProxy proxy = new JDKProxy(new SayImpl());
Say say = (Say) Proxy.newProxyInstance(SayImpl.class.getClassLoader(), SayImpl.class.getInterfaces(), proxy);
say.say("world");
}
}
运行结果:
-----begin-----
hello:world
-----end-----
二、CGLib代理案例
1)、pom.xml添加CGLib代理的依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.2.2</version>
</dependency>
2)、代码实现
public class Say {
public void say(String words) {
System.out.println("hello:" + words);
}
}
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CGLibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz) {
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("-----begin-----");
Object result = proxy.invokeSuper(obj, args);
System.out.println("-----end-----");
return result;
}
}
public class CGLibProxyTest {
public static void main(String[] args) {
CGLibProxy proxy = new CGLibProxy();
Say say = (Say) proxy.getProxy(Say.class);
say.say("world");
}
}
三、总结
1)、JDK和CGLib的区别
JDK动态代理只能对实现了接口的类生成代理,而不能针对类
CGLib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法(继承)
2)、Spring在选择用JDK还是CGLib的依据
当Bean实现接口时,Spring就会用JDK的动态代理
当Bean没有实现接口时,Spring使用CGLib来实现
可以强制使用CGLib(在Spring配置中加入<aop:aspectj-autoproxy proxy-target-class=“true”/>)
3)、JDK和CGLib的性能对比
使用CGLib实现动态代理,CGLib底层采用ASM字节码生成框架,使用字节码技术生成代理类,在JDK1.6之前比使用Java反射效率要高。唯一需要注意的是,CGLib不能对声明为final的方法进行代理,因为CGLib原理是动态生成被代理类的子类
在JDK1.6、JDK1.7、JDK1.8逐步对JDK动态代理优化之后,在调用次数较少的情况下,JDK代理效率高于CGLib代理效率,只有当进行大量调用的时候,JDK1.6和JDK1.7比CGLib代理效率低一点,但是到JDK1.8的时候,JDK代理效率高于CGLib代理