JDK的动态代理只能针对接口来实现,由Proxy.newProxyInstance()第二个参数能很清楚地意识到这一点。面向接口编程肯定有它自己的好处,但是如果很小很小的一个项目,我们要对每个业务类创建一个接口,也并不一定是件好事吧。
如果不创建接口,而要实现代理,我们需要用到cglib,它是一个第三方的jar包,需要额外导入。
cglib采用非常底层的字节码技术,可以为代理对象创建一个子类,并且在子类中采用方法拦截的技术,拦截所有父类方法的调用,并且织入横切逻辑。
注意,既然是为父类创建一个子类,那么final修饰的方法是不能继承的,所以final修饰的方法是不会被织入横切逻辑的。
目标类:
package spring3.aop.aop4; public class Target { public void do1() { System.out.println("Target.do1()"); } public void do2(String str) { System.out.println("Target.do2(" + str + ")"); } public void exe1() { System.out.println("Target.exe1()"); } public void exe2(String str) { System.out.println("Target.exe2(" + str + ")"); } public final void exe3() { System.out.println("Target.exe3"); } }
创建代理类 CglibProxy
package spring3.aop.aop4; 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<?> cls) { // 设定被代理类(目标类) enhancer.setSuperclass(cls); // 实例化代理类 enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("----START----"); Object result = proxy.invokeSuper(obj, args); System.out.println("----END----"); return result; } }
测试类:
package spring3.aop.aop4; public class ProxyMain { public static void main(String[] args) { CglibProxy proxy = new CglibProxy(); Target childTarget = (Target) proxy.getProxy(Target.class); childTarget.do1(); childTarget.do2("test"); childTarget.exe1(); childTarget.exe2("test"); childTarget.exe3(); } }
测试结果:
----START---- Target.do1() ----END---- ----START---- Target.do2(test) ----END---- ----START---- Target.exe1() ----END---- ----START---- Target.exe2(test) ----END---- Target.exe3
这部分没有什么要讲的,大家知道就可以了。
注意,加载cglib时间比jdk的反射时间要长,如果应用中频繁的动态生成新的代理,不建议使用cglib,这个根据具体需求自己判断。
spring的aop是通过jdk动态代理或者cglib动态代理为目标bean织入横切逻辑的。