Spring AOP原生方式实现

概述

Spring 整合AspectJ框架实现AOP只是Spring框架中AOP的一种实现方式,此方式相对比较简单,实现方便。但此方式底层还是要转换为Spring原生AOP的实现,Spring AOP原生方式实现的核心有三大部分构成,分别是:

  • JDK代理。
  • CGLIB代理
  • org.aopalliance包下的拦截体系

架构分析

在这里插入图片描述
其中DefaultAdvisorAutoProxyCreator这个类功能更为强大,这个类的奇妙之处是他实现BeanPostProcessor接口,当ApplicationContext读取所有的Bean配置信息后,这个类将扫描上下文,寻找所有的Advisor对象(一个Advisor由切入点和通知组成),将这些Advisor应用到所有符合切入点的Bean中。

实际案例

项目结构

在这里插入图片描述

PjApplication主启动类

主启动类 配置 DefaultAdvisorAutoProxyCreator对象 ,一般是配置在配置类上,这里为了简化代码,放在主启动类上.

@SpringBootApplication
public class PjApplication {
    
    
	
	@Bean 
	public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
    
    
		//此对象会在容器启动时扫描Advisor对象,然后基于切入点为目标对象创建代理对象
		//然后再执行切入点方法时,自动执行Advice对象通知方法
		return new DefaultAdvisorAutoProxyCreator();
	}
	public static void main(String[] args) {
    
    
		SpringApplication.run(CgbSourceAop01Application.class, args);
	}
}

@Bean注解应用于配置类中(使用了@Configuration修饰)
@Bean描述的方法其返回值会交给spring管理,spring管理这个bean默认bean名字为方法名

  1. DefaultAdvisorAutoProxyCreator对象会在容器启动时扫描Advisor对象
  2. 然后基于切入点为目标对象创建代理对象
  3. 然后再执行切入点方法时,自动执行Advice对象通知方法

RequiredLog 注解

/**借助此注解描述切入点方法*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface RequiredLog {
    
    

}

service 接口

public interface MailService {
    
    
	  boolean sendMsg(String msg);
}

MailServiceImpl 目标方法实现类

@Service
public class MailServiceImpl implements MailService {
    
    
	
	@RequiredLog //希望这个注解描述的方法为一个切入点方法(目标方法)
	@Override
	public boolean sendMsg(String msg) {
    
    
		//System.out.println("start:"+System.currentTimeMillis());
		System.out.println("send "+msg);
		//System.out.println("end:"+System.currentTimeMillis());
		return true;
	}
}

LogAdvice 通知方法

继承 MethodInterceptor接口

/**
 *  日志通知对象
 */
public class LogAdvice implements MethodInterceptor {
    
    
	

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
    
    
		System.out.println("start:"+System.currentTimeMillis());
		Object result=invocation.proceed();//执行目标方法
		System.out.println("end:"+System.currentTimeMillis());
		return result;
	}
}
  • 切入点对应的目标方法执行之前执行,可以在目标方法执行之前和之后做点拓展业务
  • invocation连接点对象(封装了要执行的目标方法信息,可以通过反射调用目标方法)

LogAdvisor 顾问 (内部注册通知,判断切入点方法)

实现啦 Advisor接口

Spring容器在启动时会基于BeanPostProcessor找到所有的Advisor对象(顾问),并基于Advisor对象中切入点的描述为目标对象创建代理对象.当执行目标方法时会执行Advisor对象关联通知.

@Component
public class LogAdvisor extends StaticMethodMatcherPointcutAdvisor {
    
    
	private static final long serialVersionUID = -3987392064269894257L;
	public LogAdvisor() {
    
    
		//在advisor内部注册一个日志通知
		setAdvice(new LogAdvice());
	}
    /**
     * 
     * matches方法用于判定方法参数中的method是否为一个切入点方法,当它的返回值
     * 	为true时,表示参数中的method对象为一个切入点方法.
     * @param method 对应了目标方法对象(可能是目标方法所在类的父类方法对象)
     * @param targetClass 代表目标对象类型
     */
	@Override
	public boolean matches(Method method, Class<?> targetClass) {
    
    
		try {
    
    
		    Method targetMethod=
		    targetClass.getMethod(method.getName(), method.getParameterTypes());
		    //检测目标方法上是否有requiredLog注解
		    return targetMethod.isAnnotationPresent(RequiredLog.class);
		}catch(Exception e) {
    
    
			return false;
		}
	}

}

测试 Tests

@SpringBootTest
public class MailServiceTests {
    
    

	@Autowired
	private MailService mailService;
	@Test
	void testSendMsg() {
    
    
		mailService.sendMsg("hello cgb2006");
	}
}

在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_48052161/article/details/108700453