参考链接:https://blog.csdn.net/yangzsirr/article/details/120915005
https://blog.csdn.net/wang489687009/article/details/121099165
1、advice
解释为通知,表示 Aspect 在特定的 连接点(Join point)采取的操作。包括 “around”, “before” and “after 等。和切点(pointCut)组成一个切面(aspect)可以有多个通知
。
补充:
①Pointcut:切点,决定advice应该作用于那个连接点,比如根据正则等规则匹配哪些方法需要增强(Pointcut 目前有getClassFilter(类匹配),getMethodMatcher(方法匹配),Pointcut TRUE (全匹配))
②JoinPoint:连接点,就是spring允许你是通知(Advice)的地方,基本每个方法的前、后(两者都有也行),或抛出异常是时都可以是连接点,spring只支持方法连接点。其他如AspectJ还可以让你在构造器或属性注入时都行
可以看出MethodInterceptor
是功能最强大的,它能够处理 BeforeAdvice、AroundAdvice、AfterAdvice、ThrowsAdvice
2、advisor
解释为通知者,它持有 Advice,是Advice和PointCut的结合,它是将Advice注入程序中Pointcut位置的代码。org.springframework.aop.support.DefaultPointcutAdvisor是最通用的Advisor类,在Advisor中Advice和PointCut是一对一的只包含一个通知
。
从接口方法很容易看到Advisor就是Advice和Pointcut的组合,从中可以获取Advice和Pointcut。
3、Advised
AOP 代理工厂配置类接口。提供了操作和管理 Advice 和 Advisor 的能力。
Spring提供的类org.springframework.aop.framework.ProxyFactoryBean是创建AOP的最基本的方式。它是个工厂Bean,然后我们可以自定义我们的代理实现逻辑,最终交给Spring容器管理即可。
1、HandlerInterceptoer拦截的是请求地址
,所以针对请求地址做一些验证、预处理等操作比较合适。当你需要统计请求的响应时间时MethodInterceptor将不太容易做到,因为它可能跨越很多方法或者只涉及到已经定义好的方法中一部分代码。
2、MethodInterceptor是AOP项目中的拦截器(注:不是动态代理拦截器),它拦截的目标是方法
。
3、另外,还有一个跟拦截器类似的东西----Filter。Filter是Servlet规范规定的,不属于spring框架,也是用于请求的拦截。但是它适合更粗粒度的拦截,在请求前后做一些编解码处理、日志记录等。
实现MethodInterceptor拦截器大致也分为两种:
(1)MethodInterceptor接口;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
public class MyAdvice implements MethodInterceptor {
/**
* 此方法可以在目标业务方法执行之前和之后添加扩展逻辑
*/
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("start:" + System.nanoTime());
Object result = methodInvocation.proceed();//执行目标方法
System.out.println(result);
System.out.println("end:" + System.nanoTime());
return result;
}
}
(2)利用AspectJ的注解配置;
@Component
@Aspect
public class MyAspect {
@Pointcut("execution(public * com.example.demo.service.impl.UserServiceImpl.*(..))")
public void pointCut(){
}
@Around("pointCut()")
public void aroundAOP(ProceedingJoinPoint joinPoint){
try {
System.out.println("前置通知");
joinPoint.proceed();
System.out.println("返回通知");
} catch (Throwable throwable) {
System.out.println("异常通知");
} finally {
System.out.println("后置通知");
}
}
}
方式一:
1、定义TargetAnnotation 注解,用于描述目标业务对象
/**借助此注解描述切入点方法*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TargetAnnotation {
}
2、定义MyAdvice对象,基于此对象为目标业务对象做方法增强。
public class MyAdvice implements MethodInterceptor {
/**
* 此方法可以在目标业务方法执行之前和之后添加扩展逻辑
*/
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("start:" + System.nanoTime());
Object result = methodInvocation.proceed();//执行目标方法
System.out.println(result);
System.out.println("end:" + System.nanoTime());
return result;
}
}
3、创建MyAdvisor对象,在对象内部定义要切入扩展功能的点以及要应用的通知(Advice)对象。
@Component
public class MyAdvisor extends StaticMethodMatcherPointcutAdvisor {
private static final long serialVersionUID = 7022316764822635205L;
public MyAdvisor() {
//在特定切入点上要执行的通知
setAdvice(new MyAdvisor());
}
//Pointcut
//方法返回值为true时,则可以为目标方法对象创建代理对象
@Override
public boolean matches(Method method,Class<?> targetClass) {
try {
Method targetMethod = targetClass.getMethod(method.getName(),
method.getParameterTypes());
return targetMethod.isAnnotationPresent(TargetAnnotation.class);
} catch(Exception e) {
return false;
}
}
}
4、BeanPostProcessor类型对象初始化
在项目启动类中,添加DefaultAdvisorAutoProxyCreator对象初始化方法,基于此对象在容器启动时扫描所有Advisor对象,然后基于切入点描述的目标方法为目标对象创建代理对象,代码如下:
@SpringBootApplication
public class DemoApplication {
//@Bean注解应用于配置类中(使用了@Configuration修饰)
//@Bean描述的方法其返回值会交给spring管理,spring管理这个bean默认bean名字为方法名
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
//此对象会在容器启动时扫描Advisor对象,然后基于切入点为目标对象创建代理对象
//然后再执行切入点方法时,自动执行Advice对象通知方法
return new DefaultAdvisorAutoProxyCreator();
}
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
5、目标对象
@Service
public class BookServiceImpl extends ServiceImpl<BookDao, Book> implements BookService {
@TargetAnnotation
@Override
public Book getDataByBookId(int bookId) {
Book book = baseMapper.getDataByBookId(bookId);
return book;
}
}
6、测试
@Autowired
private BookService bookService;
@Test
public void test() {
bookService.getDataByBookId(1);
}
方式二:
1、定义MyAdvice对象,基于此对象为目标业务对象做方法增强。
public class MyAdvice implements MethodInterceptor {
/**
* 此方法可以在目标业务方法执行之前和之后添加扩展逻辑
*/
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("start:" + System.nanoTime());
Object result = methodInvocation.proceed();//执行目标方法
System.out.println(result);
System.out.println("end:" + System.nanoTime());
return result;
}
}
2、目标对象
@Service
public class BookServiceImpl extends ServiceImpl<BookDao, Book> implements BookService {
@Override
public String getMessage(String str) {
return str;
}
}
3、通过ProxyFactory 自定义代理逻辑测试
@Autowired
private BookService bookService;
@Test
public void test() {
ProxyFactory proxyFactory = new ProxyFactory();
//注:这里如果直接new,那么该类就不能使用@Autowired之类的注入,因此建议还是从容器中去拿
//proxyFactory.setTarget(new BookServiceImpl());//cglib代理
proxyFactory.setTarget(bookService); //jdk代理
//若没有实现接口,那就会采用cglib去代理,否则就是jdk代理
//proxyFactory.setInterfaces(BookService.class);
//若设置为true,强制使用cglib,默认是false的
//proxyFactory.setProxyTargetClass(true);
proxyFactory.addAdvice(new MyAdvice());
Object proxy = proxyFactory.getProxy();
BookService methodInterceptor = (BookService) proxy;
methodInterceptor.getMessage("测试");
}