前景提要
监控方法性能、执行时间、记录日志等
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");