Spring AOP的源码中用到了两种动态代理来实现拦截切入功能:jdk动态代理和cglib动态代理。两种方法同时存在,各有优劣。jdk动态代理是由内部java的反射机制来实现的,cglib动态代理底层则是借助asm来实现的。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效(可以通过将asm生成的类进行缓存,这样解决asm生成类过程低效问题)。还有一点必须注意:jdk动态代理的应用前提,必须是目标类基于统一的接口。如果没有上述前提,jdk动态代理不能应用。由此可以看出,jdk动态代理有一定的局限性,cglib这种第三方类库实现的动态代理应用更加广泛,且在效率上更有优势。
cglib做动态代理时不要求被代理类实现统一接口。
来看一个我自己编写的jdk和cglib例子:
加入
代理类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import dynamicProxy.service.IHandler;
/**
* Created by liukang Date: 2017/1/23 Time: 12:07 jdk 动态代理测试类T
*/
public class MyInvocationHandlerTest <ProxyClass> implements FactoryBean<ProxyClass> {
private ProxyClass iHandler;
/**
* 代理类
*/
private ProxyClass proxyIHandler;
private _ProxyTypeEnum proxyTypeEnum;
public MyInvocationHandlerTest(ProxyClass iHandler,_ProxyTypeEnum proxyTypeEnum){
this.iHandler = iHandler;
this.proxyTypeEnum = proxyTypeEnum;
}
public ProxyClass getObject() throws Exception {
if(this.proxyTypeEnum.equals(_ProxyTypeEnum.JDK)){
if (proxyIHandler == null) {
_InvocationHandler myInvocationHandler = new _InvocationHandler();
proxyIHandler = (ProxyClass) Proxy.newProxyInstance(this.iHandler.getClass().getClassLoader(),
this.iHandler.getClass().getInterfaces(), myInvocationHandler);
}
}
if(this.proxyTypeEnum.equals(_ProxyTypeEnum.CGLIB)){
Enhancer e = new Enhancer();
e.setSuperclass(iHandler.getClass());
e.setCallback(new _CglibProxy());
proxyIHandler = (ProxyClass) e.create();
}
return proxyIHandler;
}
public Class<?> getObjectType() {
return IHandler.class;
}
public boolean isSingleton() {
return true;
}
public enum _ProxyTypeEnum{
JDK,CGLIB;
}
/**
* jdk代理类实现
*/
public class _InvocationHandler implements InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object proxyObject = null;
if ("handle".equals(method.getName())) {
System.out.println("before handle!");
proxyObject = method.invoke(MyInvocationHandlerTest.this.iHandler, args);
System.out.println("end handle!");
} else {
proxyObject = method.invoke(MyInvocationHandlerTest.this.iHandler, args);
}
return proxyObject;
}
}
/**
* cglib代理类实现 cglib的好处是 代理的类不用都实现同一个接口
*/
public class _CglibProxy implements MethodInterceptor{
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("++++++before " + methodProxy.getSuperName() + "++++++");
System.out.println(method.getName());
Object o1 = methodProxy.invokeSuper(o, objects);
System.out.println("++++++end " + methodProxy.getSuperName() + "++++++");
return o1;
}
}
}
service层:
/**
* Created by liukang
* Date: 2017/1/23
* Time: 12:15
* 处理器接口
*/
public interface IHandler {
void handle(Object...objects);
}
package dynamicProxy.service.impl;
import dynamicProxy.model.UserEntity;
import dynamicProxy.service.IHandler;
/**
* Created by liukang Date: 2017/1/23 Time: 12:28 姓名处理类
*/
public class NameHandler implements IHandler {
public void handle(Object... objects) {
System.out.println("nameHandler start!");
if (objects == null || objects.length < 1) {
System.out.println("nameHandler objects is null");
return;
}
UserEntity user = (UserEntity) objects[0];
user.setName(user.getName()+" Handle");
System.out.println("nameHandler done!");
}
}
model层:
package dynamicProxy.model;
/**
* Created by liukang
* Date: 2017/1/23
* Time: 12:48
*/
public class UserEntity {
private String name;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public UserEntity(String name,int age){
this.name = name;
this.age = age;
}
}
测试类:
import dynamicProxy.model.UserEntity; import dynamicProxy.service.IHandler; import dynamicProxy.service.impl.NameHandler; /** * Created by liukang * Date: 2017/1/23 * Time: 12:34 */ public class TestProxy { public static void main(String args[]){ //jdk MyInvocationHandlerTest<IHandler> myInvocationHandlerTest = new MyInvocationHandlerTest(new NameHandler(), MyInvocationHandlerTest._ProxyTypeEnum.JDK); UserEntity user = new UserEntity("name",16); try { IHandler nameHandler = myInvocationHandlerTest.getObject(); nameHandler.handle(user); } catch (Exception e) { e.printStackTrace(); } System.out.println(user.getName()); //cglib MyInvocationHandlerTest<IHandler> myInvocationHandlerTest2 = new MyInvocationHandlerTest(new NameHandler(), MyInvocationHandlerTest._ProxyTypeEnum.CGLIB); UserEntity user2 = new UserEntity("name2",18); try { IHandler nameHandler2 = myInvocationHandlerTest2.getObject(); nameHandler2.handle(user2); } catch (Exception e) { e.printStackTrace(); } System.out.println(user2.getName()); } }