AOP的设计思想
作者:bin一、静态代理:
静态代理就是实现一个「新类」他和「原类」实现同一个接口,使用时替换「原类」以达到增强的效果
package com.zengbingo.proxyStatic; public class proxyStatic { public static void main(String[] args) { A a = new A(); B b = new B(a); b.print(); } /** * 「原类」 * 实现print */ public static class A implements print{ @Override public void print(){ System.out.println("A你好"); } } /** * 「新类」 * 实现同一个接口print */ public static class B implements print{ //构造方法传入「原类」 B(A source){ a=source; } public static A a; /** * 增强 */ @Override public void print(){ System.out.println("B之前"); a.print(); System.out.println("B之后"); } } public interface print{ public void print(); } }
静态代理就是需要在每个需要被代理的「原类」都实现一个「新类」,但是一些重复的功能我们可能不希望重复写,例如上面的例子,例如还有一个C类也需要被增强,你就要在构造更多的B来满足要求
二、动态代理
动态代理即将代理类的生层过程抽出来,由代理对象生成器去生成增强的代理类。
动态代理一般有两种方式,一种基于反射实现的「JDK」、另一种基于字节码生成的CGLIB代理。
1.JDK代理
JDK代理类的生成交给Proxy类来实现,JDK代理通过反射实现来一个代理类,所有的方法都通过InvocationHandler的invoker进行拦截
public class JdkProxy { public static void main(String[] arg) { A real1 = new A(); ProxyAHandler proxyAHandler = new ProxyAHandler(real1); /** * 生成代理类的过程交给Proxy去做 */ Print proxyA = (Print) Proxy.newProxyInstance( A.class.getClassLoader(), new Class[]{Print.class}, proxyAHandler); proxyA.print(); } private static class A implements Print { @Override public void print() { System.out.println("A你好"); selfTransfer(); } @Override public void selfTransfer(){ System.out.println("A我在内部被调用不会被代理"); } } private static class ProxyAHandler implements InvocationHandler { public ProxyAHandler(Object source) { this.source = source; } private Object source; /** * 不管是什么方法,都会被代理,除了类内部自己调用,因为类内部自己调用,没有走到代理类 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println(method.getName() + ",invoke前"); Object o = method.invoke(source, args); System.out.println(method.getName() + ",invoke后"); return o; } } private interface Print { void print(); //自己调自己 void selfTransfer(); } }
print,invoke前 A你好 A我在内部被调用不会被代理 print,invoke后
2.CGLIB代理
通过使用Enhancer方法,实现一个继承「原类」的「新类」,对「原类」方法进行拦截增强,代码如下:
public class CglibProxy { public static void main(String[] arg) { Enhancer enhancer = new Enhancer(); //设置需要继承哪个类 enhancer.setSuperclass(A.class); //设置拦截的方法 enhancer.setCallback(new AInterceptorImpl()); //构造代理对象 A a = (A)enhancer.create(); a.print(); } public static class A{ public void print() { System.out.println("A你好"); selfTransfer(); } public void selfTransfer(){ System.out.println("A在内部也会被代理"); } } private static class AInterceptorImpl implements MethodInterceptor { @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println(method.getName() + ",invoke前"); Object res = methodProxy.invokeSuper(object, args); System.out.println(method.getName() + ",invoke后"); return res; } } }
输出
print,invoke前 A你好 selfTransfer,invoke前 A在内部也会被代理 selfTransfer,invoke后 print,invoke后
3.spring 中的CGLIB代理
我们知道spring中的AOP,在类内部调用时是不会触发拦截的,上面的JDK是满足要求的,CGLIB是不满足要求的。那么spring中的CGLIB是如何实现类内部调用不触发的呢?
public class SpringCglibProxy { public static void main(String[] arg) { Enhancer enhancer = new Enhancer(); //设置需要继承哪个类 enhancer.setSuperclass(A.class); //设置拦截的方法 A sourceA = new A(); enhancer.setCallback(new AInterceptorImpl(sourceA)); //构造代理对象 A a = (A)enhancer.create(); a.print(); } public static class A{ public void print() { System.out.println("A你好"); selfTransfer(); } public void selfTransfer(){ System.out.println("A在内部不会被代理"); } } private static class AInterceptorImpl implements MethodInterceptor { //类似JDK,将source类传入使用 private A a; AInterceptorImpl(A source){ a=source; } @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.out.println(method.getName() + ",invoke前"); //invoke指定类,而不是super类 Object res = methodProxy.invoke(a, args); System.out.println(method.getName() + ",invoke后"); return res; } } }
输出:
print,invoke前 A你好 A在内部不会被代理 print,invoke后