AOP技术它利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为”Aspect”,即切面。所谓”切面”,简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性.
1.切面(aspect):散落在系统各处的通用的业务逻辑代码,切面用来装载pointcut和advice;
2.通知(advice):指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环 绕通知五类;
3.连接点(joinpoint):被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring 中连接点指的就是被拦截到的方法
4.切入点(pointcut):拦截的方法,连接点拦截后变成切入点
代理方式:
Spring中 AOP中的两种代理: JDK动态代理;CGLIB代理
JDK动态代理:
动态代理机制的实现主要由 java.lang.reflect.Proxy 类和java.lang.reflect.InvocationHandler接口,只能对实现了相应Interface的类使用,如果某个类没有实现任何的Interface,就无法使用动态代理对其产生相应的代理对象!
在默认情况下,如果Spring AOP发现目标实现了相应的Interface,则采用动态代理为其生成代理对象实例;而如果目标对象没有实现任何的Interface,Spring AOP会尝试使用CGLIB动态字节码生成类库,为目标对象生成代理对象实例!
CGLIB代理:
使用CGLIB扩展对象行为的原理是:对目标对象进行继承扩展,为其生成相应的子类,而子类可以通过覆写来扩展父类的行为;
使用CGLIB类库,实现一个net.sf.cglib.proxy.Callback,或者使用net.sf.cglib.proxy.MethodInterceptor(继承自Callback),通过Enhancer为目标对象动态生成一个子类,将RequestCallback的横切逻辑附加到该子类中
相比于动态代理,CGLIB的优势就是,可以为没有实现任何接口的类进行扩展;
使用 CGLIB 对类进行扩展的唯一限制就是 无法对 final 方法进行覆写
应用:
定义扫描注解:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RunningLog {
}
定义切面:
@Aspect
@Component
public class RunningAspect implements run {
@Pointcut("@annotation(com.xxx.xxx.running.service.RunningLog)")
public void updatePointCut(){};
@Around(value = "updatePointCut()")
public Object updateAround(ProceedingJoinPoint jp) throws Throwable{
... ....
}
}
调用时,在方法上加上@RunningLog注解即可。
相关源码
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
Class targetClass = config.getTargetClass();
if (targetClass == null) { throw new AopConfigException(".. ...");}
if (targetClass.isInterface()) {return new JdkDynamicAopProxy(config);}
return CglibProxyFactory.createCglibProxy(config);
}else {
return new JdkDynamicAopProxy(config);
}
}
此代码解释了为什么配置文件中
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />
proxy-target-class="true" 为true可是dao的代理类还是$Proxy,使用的是JDK动态代理