关注点分离:不同的问题交给不同的部分去解决
- 面向切面编程AOP
- 通用化功能代码的实现,对应的就是所谓的切面(Aspect)
- 业务功能代码和切面代码分开后,架构将变得高内聚低耦合
- 确保功能的完整性:切面最终需要被合并到业务中(Weave)
AOP的三种织入方式
- 编译时织入:需要特殊的Java编译器,如AspectJ
- 类加载时织入:需要特殊的Java编译器,如AspectJ和AspectWerkz
- 运行时织入:Spring采用的方式,通过动态代理的方式,实现简单
AOP的主要名词概念
- Aspect:通过功能的代码实现
- Target:被织入Aspect的对象
- Join Point:可以作为切入点的机会,所有方法都可以作为切入点
- Pointcut:Aspect实际被应用在的Join Point,支持正则
- Advice:类里的方法以及这个方法如何织入到目标方法的方式
Advice的种类
- 前置通知( Before )
- 后置通知( AfterReturning )
- 异常通知( AfterThrowing )
- 最终通知( After )
- 环绕通知( Around )
AOP的实现:JdkProxy和Cglib
- 由AopProxyFactory根据AdvisedSupport对象的配置来决定
- 默认策略如果目标类是接口,则用JDKProxy来实现,否则用后者
- JDKProxy的核心:InvocationHandler接口和Proxy类
- Cglib:以继承的方式动态生成目标类的代理( 所以某个类被标记成final是无法生成动态代理的 )
2
- JDKProxy:通过Java的内部的反射机制来实现
- Cglib:借助ASM实现
- 反射机制在生成类的过程中比较高效
- ASM在生成类之后的执行过程中比较高效( 可以将ASM生成的类进行缓存,来解决生成类低效的过程)
代理模式:接口 + 真实实现类 + 代理类
例
@Service
public class AopDemo1 {
public String sayHello(){
System.out.println("hello");
return "return hello";
}
}
@Aspect
@Component
public class RequestLogAspect {
@Pointcut("execution(* com.example.demo.aop.demo.*.*(..))")
public void webLog(){}
@Before("webLog()")
public void deBefore(JoinPoint joinPoint){
System.out.println("@Before @Before @Before");
}
@AfterReturning( returning = "ret", pointcut = "webLog()")
public void doAfterReturning(Object ret){
System.out.println("@AfterReturning @AfterReturning @AfterReturning " + ret);
}
}