前景提要
监控方法性能、执行时间、记录日志等
AOP( Aspect Oriented Programming)面向方面编程。
在AOP中,需要定义一个Aspect(切面)类来编写需要横切业务的逻辑代码,例如上面提到的性能监控代码。此外,还需要通过一个条件来匹配想要拦截的类,这个条件在AOP中称为PointCut(切点)。
技术点
代理技术
使用Spring提供的AOP技术
使用动态代理技术实现AOP框架
使用ThreadLocal技术
数据库事物管理机制
使用AOP框架实现事物控制
一、代理技术
代理,Proxy。aop是代理的一种实现。Http代理等
1.1、静态代理
示例
public interface Hello { void say(String name); }
实现
public class HelloImpl implements Hello { @Override public void say(String name) { System.out.println("Hello! " + name); } }
如,在说前后增加操作。
初级代理实现:
public class HelloProxy implements Hello { private Hello hello; public HelloProxy() { this.hello = new HelloImpl(); } @Override public void say(String name) { before(); hello.say(name); after(); } private void before(){ System.out.println("Before"); } private void after(){ System.out.println("After"); } }
测试主类:
Hello helloProxy = new HelloProxy(); helloProxy.say("muzixu");
输出:
Before Hello! muzixu After
其实,以上helloProxy 就是代理。
1.2、JDK动态代理
第一次 编写
使用JDK方案的一个动态代理
public class DynamicProxy implements InvocationHandler { private Object target; public DynamicProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(target,args); after(); return result; } private void before(){ System.out.println("Before"); } private void after(){ System.out.println("After"); } }
在DynamicProxy 类中定义了一个Object的target变量,他就是被代理的目标对象。通过构造函数来初始化【即注入】。
该类实现了InvocationHandler 接口,需要实现的方法即invoke。在该方法中,直接通过反射去invoke method,在调用前后分别before,after,最后返回结果。
调用
Hello hello=new HelloImpl(); DynamicProxy dynamicProxy=new DynamicProxy(hello); Hello helloProxy = (Hello)Proxy.newProxyInstance(hello.getClass().getClassLoader(), hello.getClass().getInterfaces(), dynamicProxy); helloProxy.say("muzixu");
用通用的DynamicProxy 类去包装HelloImpl实例,然后在调用JDK提供的Proxy类的工厂方法newProxyInstance去动态的创建一个Hello接口的代理类,最后调度用这个代理类的方法。
结果同上一致。
第二次 优化
public class DynamicProxy2 implements InvocationHandler { private Object target; public DynamicProxy2(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { before(); Object result = method.invoke(target, args); after(); return result; } public <T> T getProxy() { return (T) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } private void before() { System.out.println("Before"); } private void after() { System.out.println("After"); } }
使用
DynamicProxy2 dynamicProxy=new DynamicProxy2(new HelloImpl()); Hello helloProxy = dynamicProxy.getProxy(); helloProxy.say("muzixu");
其实就是将实例化过程抽象。
对比一下
名称 | 优点 | 缺点 |
静态代理 | 接口变了,实现类需要变,代理类也要变 | |
JDK动态代理 | 接口变了,代理类不变 | 无法代理没有实现任何一个接口的类 |
CGlib动态代理 |
运行期间动态生成字节码的工具 也就是动态生成代理类 |
1.3、CGlib动态代理
spring,hibernate等使用
pom:
<dependencies> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.1</version> </dependency> </dependencies>
第一次实例
public class CGLibProxy implements MethodInterceptor { public <T> T getProxy(Class<T> cls) { return (T) Enhancer.create(cls,this); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { before(); Object result = methodProxy.invokeSuper(o,objects); after(); return result; } private void before() { System.out.println("Before"); } private void after() { System.out.println("After"); } }
使用
CGLibProxy proxy = new CGLibProxy(); Hello hello = proxy.getProxy(HelloImpl.class); hello.say("muzixu");
第二次 单例模式构建
public class CGLibSingleProxy implements MethodInterceptor { private static CGLibSingleProxy instance = new CGLibSingleProxy(); private CGLibSingleProxy(){ } public static CGLibSingleProxy getInstance(){ return instance; } public <T> T getProxy(Class<T> cls) { return (T) Enhancer.create(cls,this); } @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { before(); Object result = methodProxy.invokeSuper(o,objects); after(); return result; } private void before() { System.out.println("Before"); } private void after() { System.out.println("After"); } }
调用
Hello hello = CGLibSingleProxy.getInstance().getProxy(HelloImpl.class); hello.say("muzixu");