Spring之AOP
1.SpringAOP的介绍
面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP的功能将切面织入到主业务逻辑中。所谓交叉业务逻辑是指,通用的、与主业务逻辑无关的代码,如安全检查、事务、日志等。若不使用AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样,会使主业务逻辑变的混杂不清
添加对应的依赖
org.springframework
spring-context
5.1.17.RELEASE
org.aspectj
aspectjweaver
1.9.1
2. AspecJ的使用
2.1 放开AspectJ
@Configuration
@EnableAspectJAutoProxy // 放开AspectJ的使用
@ComponentScan
public class JavaConfig {
public static void main(String[] args) {
ApplicationContext ac = new AnnotationConfigApplicationContext(JavaConfig.class);
IUserService bean = ac.getBean(IUserService.class);
bean.fun1();
}
}
2.2 创建切面类
@Aspect // 显示的表明当前类是一个切面类
@Component // 将该对象加载到IoC容器中
public class MyAspectJ01 {
/**
* 要增强目标对象的方法
* 指定目标对象
* 切入点表达式
*/
@Before("execution(* com.zsc.service.impl.*.fun2(..))")
public void aspectMethod01(){
System.out.println("before ....");
}
}
切入点表达式
execution表达式
语法: execution([访问权限类型] 返回值类型 [全限定类名] 方法名(参数名) [抛出的异常类型])
实例演示:
execution(public * *(. .))
指定切入点为:任意公共方法。
execution(* set *(. .))
指定切入点为:任何一个以“set”开始的方法。
execution(* com.xyz.service.*.*(. .))
指定切入点为:定义在service包里的任意类的任意方法。
execution(* com.xyz.service. .*.*(. .))
指定切入点为:定义在service包或者子包里的任意类的任意方法。“..”出现在类名中时,
后面必须跟“*”,表示包、子包下的所有类。
execution(* *.service.*.*(. .))
指定只有一级包下的serivce子包下所有类(接口)中的所有方法为切入点
execution(* *. .service.*.*(. .))
指定所有包下的serivce子包下所有类(接口)中的所有方法为切入点
2.3 通知类型
@Component
@Aspect
public class MyAspectJ02 {
/**
* 前置通知
*/
@Before("execution(* com.zsc.service.impl.*.*(..))")
public void before(){
System.out.println("before ...");
}
/**
* 后置通知 获取返回结果
* @param res
*/
@AfterReturning(value = "within(com.zsc.service.impl.*)",returning = "res")
public void afterReturning(Object res){
System.out.println("后置通知..." + res);
}
/**
* 环绕通知
* @param proceedingJoinPoint
* @return
* @throws Throwable
*/
@Around(value = "within(com.zsc.service.impl.*)")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("目标对象before....");
Object[] args = proceedingJoinPoint.getArgs();
Object res = proceedingJoinPoint.proceed(); // 目标对象方法执行
System.out.println("目标对象after...." + res);
return res;
}
/**
* 异常通知
* @param ex
*/
@AfterThrowing(value = "within(com.zsc.service.impl.*)",throwing = "ex")
public void afterThrowing(Exception ex){
System.out.println("异常通知产生了..." + ex);
}
/**
* 最终通知
*/
@After(value = "within(com.zsc.service.impl.*)")
public void after(){
System.out.println("最终通知...");
}
}
3. AOP源码浅析
AOP的实现主要是采用的代理对象,对目标方法起到一个增强的作用。初始化Bean
/ 对象DI的实现
this.populateBean(beanName, mbd, instanceWrapper);
// 获取目标兑现对应的代理类
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
先执行initializeBean方法
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareMethods(beanName, bean);
return null;
}, this.getAccessControlContext());
} else {
this.invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = this.applyBeanPostProcessorsBeforeInitialization(bean, beanName);
}
try {
this.invokeInitMethods(beanName, wrappedBean, mbd);
} catch (Throwable var6) {
throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6);
}
if (mbd == null || !mbd.isSynthetic()) {
// 进入
wrappedBean = this.applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
进入到applyBeanPostProcessorsAfterInitialization方法中
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {
if (bean != null) {
Object cacheKey = this.getCacheKey(bean.getClass(), beanName);
if (this.earlyProxyReferences.remove(cacheKey) != bean) {
// 进入
return this.wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
protected Object createProxy(Class beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (this.shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
this.evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
this.customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (this.advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 获取代理对象并且返回
return proxyFactory.getProxy(this.getProxyClassLoader());
}
最终获取代理对象并返回
代理对象方法请求肯定执行Invoke方法
protected Object createProxy(Class beanClass, @Nullable String beanName, @Nullable Object[] specificInterceptors, TargetSource targetSource) {
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory)this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.copyFrom(this);
if (!proxyFactory.isProxyTargetClass()) {
if (this.shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
} else {
this.evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
Advisor[] advisors = this.buildAdvisors(beanName, specificInterceptors);
proxyFactory.addAdvisors(advisors);
proxyFactory.setTargetSource(targetSource);
this.customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (this.advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
// 获取代理对象并且返回
return proxyFactory.getProxy(this.getProxyClassLoader());
}
在该方法中会执行切面对应的前置通知、后置通知等方法
4. 总结
SpringAOP是Spring中一个核心思想,面向切面编程,其主要作用就是提取出公共的业务方法,对目标方法进行一个增强。其原理就是采用的代理模式。