AOP(面向切面编程):
切面:从业务逻辑分离出去的横切逻辑。典型:性能监控,日志管理,权限控制,可以从核心的业务逻辑中分离出去。
通过AOP可以解决代码耦合问题,使职责更加单一。
对于需要增强的代码,我们通常有三种解决方案:
(1)静态代理
(2)JDK动态代理
(3)CGLib动态代理
静态代理:
由程序员创建生成源代码,再对其进行编译,再程序运行时,class文件就已经存在了。(创建代理类去进行代理,但每有一个需要代理的类,都要创建相应的代理类。随着后期的发展,这种代理类会越来越多。这种方式过于繁琐,需要优化的是只生成一个代理类,让需要被代理的类都依赖这个代理类,这就需要动态代理)。
JDK动态代理:
在程序运行时,通过反射机制动态生成代理。避免编写各个繁琐的静态代理类,
动态代理三个步骤:
(1)编写自定义的InvocationHandler来实现InvocationHandler接口
(2)创建动态代理对象。
(3)代理对象调用
public class MyinvocationHandler implements InvocationHandler {
private Object target;
public MyinvocationHandler(Object target) {
this.target = target;
}
/**
*获取代理对象
*/
public Object getProxy(){
return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object rs = method.invoke(target,args);
after();
return rs;
}
public void before(){
System.out.println("开始前");
}
public void after(){
System.out.println("开始后");
}
}
JDK动态代理只能代理具有接口的类,不能代理没有接口的类,开源的CGLIb类库具有代理没有接口的类的能力,弥补了JDK的不足。
CGLIB动态代理:采用了底层的字节码技术,通过字节码技术为一个类创建子类,并在子类中对所有方法进行拦截来实现对父类方法的拦截,从而织入横切逻辑,是实现AOP的基础。
public class cglibProxy implements MethodInterceptor {
private Enhancer enhancer = new Enhancer();
public Object getProxy(Class clazz){
//传入父类字节码
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
//字节码技术创建子类
return enhancer.create();
}
//intercept用于拦截方法的调用(这里可以进行增强的处理)
public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("增强前");
//调用父类的目标方法
Object result = methodProxy.invokeSuper(obj,objects);
System.out.println("增强后");
return result;
}
}
getProxy()方法通过传入父类的字节码,创建其子类,intercept()通过对子类方法的拦截来拦截对父类目标方法的调用,顺势织入横切逻辑,达到增强的效果。
对于JDK,CGLib两种动态代理:
JDK动态代理 CGLIB动态代理 接口 必须 不需要 性能 比cglib低 比JDK高 耗时 耗时相对短 耗时长
对于单例的对象,因为无需频繁创建对象,用CGLib合适,CGLIB对于final修饰的类无法进行代理。