首先我们看一下cglib是怎么实现动态代理的:
上代码:
/**
* 被代理的某一个类,注意,没有实现任何的一个接口
*/
public class SubjectService {
public String doSomethings(String needTool){
System.out.println("用" + needTool + "做一些事情");
return "调用成功";
}
}
特别注意,cglib实现动态代理,被代理的类是可以不用实现任何接口的,就像上面一个普通类,
但是要注意的是,这个普通的类不能用final修饰,因为cglib技术是动态生成字节码技术,这个动态代理会生成一个继承被代理类的类的字节码。(很拗口)
接下来就是要写一个方法增强类了
public class SubjectMethodInterceptor implements MethodInterceptor {
/**
* obj:cglib生成的代理对象 "this", the enhanced object(增强的对象)
* method:被代理对象方法 intercepted Method 拦截(代理)的方法
* args:方法入参 argument array; primitive types are wrapped (参数数组,原始类型被包装)
* proxy: 代理方法 用户调用super的非拦截(没有代理)的方法,但是是可能被调用
*/
public Object intercept(Object obj, java.lang.reflect.Method method,
Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("======做某事之前准备======");
Object object = proxy.invokeSuper(obj, args);
System.out.println("======做某事之后收尾======");
return object;
}
}
注意上面参数的注释
接下来就是要测试了
public class CglibTest {
public static void main(String[] args) {
// 通过CGLIB动态代理获取代理对象的过程
Enhancer enhancer = new Enhancer();
// 设置enhancer对象的父类
enhancer.setSuperclass(SubjectService.class);
// 设置enhancer的回调对象
enhancer.setCallback(new SubjectMethodInterceptor());
// 创建代理对象(增强对象)
SubjectService proxy= (SubjectService)enhancer.create();
// 通过代理对象调用目标方法
proxy.doSomethings("锤子");
}
}
运行结果:
======做某事之前准备======
用锤子做一些事情
======做某事之后收尾======
上面就是cglib实现动态代理的简单实现
虽然有点废话,但是还是像介绍一下cglib
CGLIB(Code Generation Library)是一个开源项目!是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java
类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。CGLIB是一个强大的高性能的
代码生成包。它广泛的被许多AOP的框架使用,例如Spring AOP为他们提供方法的interception(拦截)。CGLIB包的底层是通
过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。除了CGLIB包,脚本语言例如Groovy和BeanShell,也
是使用ASM来生成java的字节码。
值得注意的是:
当然不推荐直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。(笔者也不敢用)
经过上面的介绍,我们肯定知道了它和JDK动态代理的区别
1. cglib是基于动态生成字节码,JDK基于Java反射机制
2. cglib被代理的类可以不实现任何的接口,JDK需要实现接口
3. 效率上,Java8之后jdk的运行效率,还是生成代理的效率都比cglib高。
但是cglib虽然效率上已经落后,但还是有应用的,springAOP中,要实现接口的,用的是JDK代理,没有实现人任何接口的还是会使用cglib技术。
就像下面的安利一样:
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
/**
* Determine whether the supplied {@link AdvisedSupport} has only the
* {@link org.springframework.aop.SpringProxy} interface specified
* (or no proxy interfaces specified at all).
*/
private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
Class<?>[] ifcs = config.getProxiedInterfaces();
return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
}
}