1 AOP各类的实现java
AOP就是面向切面编程,咱们能够从几个层面来实现AOP。编程
在编译器修改源代码,在运行期字节码加载前修改字节码或字节码加载后动态建立代理类的字节码,如下是各类实现机制的比较。 性能
类别this |
机制spa |
原理代理 |
优势日志 |
缺点code |
静态AOP对象 |
静态织入接口 |
在编译期,切面直接以字节码的形式编译到目标字节码文件中。 |
对系统无性能影响。 |
灵活性不够。 |
动态AOP |
动态代理 |
在运行期,目标类加载后,为接口动态生成代理类,将切面植入到代理类中。 |
相对于静态AOP更加灵活。 |
切入的关注点须要实现接口。对系统有一点性能影响。 |
动态字节码生成 |
在运行期,目标类加载后,动态构建字节码文件生成目标类的子类,将切面逻辑加入到子类中。 |
没有接口也能够织入。 |
扩展类的实例方法为final时,则没法进行织入。 |
|
自定义类加载器 |
在运行期,目标加载前,将切面逻辑加到目标字节码里。 |
能够对绝大部分类进行织入。 |
代码中若是使用了其余类加载器,则这些类将不会被织入。 |
|
字节码转换 |
在运行期,全部类加载器加载字节码前,前进行拦截。 |
能够对全部类进行织入。 |
2 AOP的实现机制
本章节将详细介绍AOP有各类实现机制。
2.1 动态代理
Java在JDK1.3后引入的动态代理机制,使咱们能够在运行期动态的建立代理类。使用动态代理实现AOP须要有四个角色:被代理的类,被代理类的接 口,织入器,和InvocationHandler,而织入器使用接口反射机制生成一个代理类,而后在这个代理类中织入代码。被代理的类是AOP里所说的 目标,InvocationHandler是切面,它包含了Advice和Pointcut。
2.1.1 使用动态代理
那如何使用动态代理来实现AOP。下面的例子演示在方法执行前织入一段记录日志的代码,其中Business是代理 类,LogInvocationHandler是记录日志的切面,IBusiness, IBusiness2是代理类的接口,Proxy.newProxyInstance是织入器。
清单一:动态代理的演示
package sample.proxy; public interface IBusiness { public boolean doBusiness(); }
package sample.proxy; public interface IBusiness2 { public void doBusiness2(); }
package sample.proxy; public class Business implements IBusiness, IBusiness2 { public boolean doBusiness() { System.out.println("执行业务逻辑"); return true; } public void doBusiness2() { System.out.println("执行业务逻辑2"); } }
package sample.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class DynamicProxyDemo { public static void main(String[] args) { // 须要代理的接口,被代理类实现的多个接口都必须在这里定义 Class[] proxyInterface = new Class[] { IBusiness.class, IBusiness2.class }; // 构建AOP的Advice,这里须要传入业务类的实例 LogInvocationHandler handler = new LogInvocationHandler(new Business()); // 生成代理类的字节码加载器 ClassLoader classLoader = DynamicProxyDemo.class.getClassLoader(); // 织入器,织入代码并生成代理类 IBusiness2 proxyBusiness = (IBusiness2) Proxy.newProxyInstance( classLoader, proxyInterface, handler); // 使用代理类的实例来调用方法。 proxyBusiness.doBusiness2(); ((IBusiness) proxyBusiness).doBusiness(); } /** * 打印日志的切面 */ public static class LogInvocationHandler implements InvocationHandler { private Object target; // 目标对象 LogInvocationHandler(Object target) { this.target = target; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 执行原有逻辑 Object rev = method.invoke(target, args); // 执行织入的日志,你能够控制哪些方法执行切入逻辑 if (method.getName().equals("doBusiness2")) { System.out.println("记录日志"); } return rev; } } }
输出 Java代码
输出 Java代码