动态代理模式
SpringBoot动态代理分为两种,一种是JDK的动态代理,另一种是cglib的动态代。Spring Boot默认使用JDK的动态代理,当类没有实现接口时才使用cglib的动态代理。
- JDK的动态代理,在这个例子里,被代理类实现了UserService接口,而代理类通过实现与被代理类实现的相同接口UserService,并在内部把被代理类进行注入,就可以实现对被代理类的逻辑增强。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| interface UserService{ void printUserInfo(); } class UserServiceImpl implements UserService{
@Override public void printUserInfo() { System.out.println("UserInfo print"); } }
class UserServiceProxy implements UserService{ private UserService userService;
public UserServiceProxy(UserService userService) { this.userService = userService; }
@Override public void printUserInfo() { System.out.println("========Before Print========"); userService.printUserInfo(); System.out.println("========After Print========"); } }
public class Proxy { public static void main(String[] args) { UserService userService = new UserServiceProxy(new UserServiceImpl()); userService.printUserInfo(); } }
|
- cglib动态代理,通过自定义拦截器并实现MethodInterceptor 接口来对被代理类进行拦截,并对逻辑进行增强。
1 2 3 4 5 6 7 8 9 10 11
| public class AIntercepter implements MethodInterceptor { @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("代理前,增强逻辑"); methodProxy.invokeSuper(o, objects); System.out.println("代理后,增强逻辑"); return null; } }
|
AOP的介绍
AOP(Aspect Oriented Programing):面向切面编程,将通用的逻辑从业务逻辑中分离出来。AOP把软件系统分为两个部分:核心关注点和横切关注点。业务处理的主要流程是核心关注点,与之关系不大的部分是横切关注点。横切关注点的一个特点是,他们经常发生在核心关注点的四周,而各处都基本相似。比如权限认证、日志、事务处理。Aop 的作用在于分离系统中的各种关注点,将核心关注点和横切关注点分离开来。
AOP的相关概念
关键词 |
说明 |
Joinpoint连接点 |
表示需要在程序中插入横切关注点的扩展点,连接点可能是类初始化、方法执行、方法调用、字段调用或处理异常等等 |
Pointcut切入点 |
选择一组相关连接点的模式,即可以认为连接点的集合,即符合某种条件的切入点的集合 |
Advice通知 |
在连接点上执行的行为,通知提供了在AOP中需要在切入点所选择的连接点处进行扩展现有行为的手段;包括前置通知(before advice)、后置通知(after advice)、环绕通知(around advice)。 |
Introduction引入 |
也称为内部类型声明,为已有的类添加额外新的字段或方法。 |
Aspect切面 |
横切关注点的模块化,比如日志组件。可以认为是通知、引入和切入点的组合。 |
AOP Proxy |
AOP框架使用代理模式创建的对象,从而实现在连接点处插入通知(即应用切面),就是通过代理来对目标对象应用切面。在Spring中,AOP代理可以用JDK动态代理或CGLIB代理实现,而通过拦截器模型应用切面。 |
Weaving织入 |
织入是一个过程,是将切面应用到目标对象从而创建出AOP代理对象的过程,织入可以在编译期、类装载期、运行期进行。 |
AOP相关注解
@Aspect:表示一个类是一个切面,一个切面包含了通知、切入点等。
@Poincut:表示切入的点,即程序中通用的逻辑业务,这里是请求的路径
@Before:表示在方法开始执行前执行
@After:表示在方法执行后执行
@AfterReturning: 表示在方法返回后执行
@AfterThrowing: 表示在抛出异常时执行
@Around:在方法执行前和执行后都会执行
AOP的使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| @Aspect @Component @Slf4j public class PerformanceAspect { @Around("repositoryOps()") public Object repoLogPerformance(ProceedingJoinPoint pjp) throws Throwable { long startTime = System.currentTimeMillis(); String name = "-"; String result = "Y"; try { name = pjp.getSignature().toShortString(); return pjp.proceed(); }catch (Throwable t){ result = "N"; throw t; }finally { long endTime = System.currentTimeMillis(); log.info("{};{};{}ms", name, result, endTime - startTime); } } @After("serviceOps()") public void serviceLogPerformance(JoinPoint jp){ log.info("================================================"); } @Pointcut("execution(* com.muchlab.chapter82.repository.CoffeeRepository.findOne(..))") public void repositoryOps(){
} @Pointcut("execution(* com.muchlab.chapter82.service.*.*(..))") public void serviceOps(){
} }
|
切入对象 |
说明 |
匹配注解 @target |
限制连接点匹配特定的执行对象,这些对象对应的类要有具体指定类型的注解 |
匹配注解 @args |
限制连接点匹配参数为指定注解类型的执行方法 |
匹配注解 @within |
限制连接点匹配指定注解所标注的类型 |
匹配注解 @annotation |
限制连接点匹配方法上的注解 |
匹配包或类型 within |
限制连接点匹配指定的表或类 |
匹配对象 this |
限制连接点匹配AOP代理的bean引用为指定类型的类 |
匹配对象 bean |
限制连接点匹配一个指定的bean,需要指出bean的名字 |
匹配对象 target |
限制连接点匹配目标对象为指定类型的类 |
匹配参数 args |
限制连接点匹配参数为指定类型的执行方法 |
匹配方法 execution() |
匹配连接点的执行方法 |