spring的AOP原理
spring的aop是spring的两大特性之一。spring生态圈自带的spring shiro和log4J等横切性质的模块都系统性的一些功能,如果在业务的模块中不断写这些代码可以会出现大量的重复性代码,使用aop去做这些系统性的工作,可以大大减轻代码量。
spring AOP实现的原理是使用的是设计模式中的代理模式。
实现原理:
代理模式分为两种:静态代理模式和动态代理模式
静态代理:代理类和目标类实现同样的接口,代理类中有目标类的引用。
接口
public interface IHello { void sayHello(String str); }
目标类
public class Hello implements IHello{ @Override public void sayHello(String str) { System.out.println("hello:" + str); } }
代理类
public class ProxyHello implements IHello{ private Hello hello; public ProxyHello(Hello hello){ this.hello = hello; } @Override public void sayHello(String str) { Logger.start(); hello.sayHello(str); Logger.end(); } public static void main(String[] args){ ProxyHello hello = new ProxyHello(new Hello()); hello.sayHello("张某某"); } }
静态代理有以下几个问题:
1. 如果目标类没有实现接口,怎样实现代理
2. 是不是针对不同Hello需要写很多个代理类,太麻烦了
3. 需要实现接口中的所有方法
查看文献可可知:
实际工作环境中:
使用aspectJ进行静态代理
public class Hello { public void sayHello() { System.out.println("hello"); } public static void main(String[] args) { Hello h = new Hello(); h.sayHello(); } }
编写一个aspect
public aspect TxAspect { void around():call(void Hello.sayHello()){ System.out.println("开始事务 ..."); proceed(); System.out.println("事务结束 ..."); } }
编译后的代码可以更改为:
public class Hello { public Hello() { } public void sayHello() { System.out.println("hello"); } public static void main(String[] args) { Hello h = new Hello(); sayHello_aroundBody1$advice(h, TxAspect.aspectOf(), (AroundClosure)null); } }
public void ajc$around$com_listenzhangbin_aop_TxAspect$1$f54fe983(AroundClosure ajc$aroundClosure) { System.out.println("开始事务 ..."); ajc$around$com_listenzhangbin_aop_TxAspect$1$f54fe983proceed(ajc$aroundClosure); System.out.println("事务结束 ..."); }
可以看出来代码在编译过程中已经被织入到代码中
针对上面这些问题:
java提出使用动态代理来解决这些问题
public class DynamicProxyHello implements InvocationHandler{ private Object target;//目标对象 public Object bind(Object object) { this.target = object; return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),this.target.getClass().getInterfaces(),this); } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; Logger.start(); result = method.invoke(this.target,args); Logger.end(); return result; } public static void main(String[] args){ IHello hello= (IHello) new DynamicProxyHello().bind(new Hello()); hello.sayHello("张某某"); } }
可以看出可以生成任一接口的代理类,并且针对任一方法织入增强方法,但是缺点是仍然目标类需要实现接口
第三中方式:
使用cglib来进行处理
cglib生成目标类的子类,然后将需要增强的方法重写,cglib也有局限,对于无法生成子类的类(final类)也无法处理