Spring之AOP

1.SpringAOP的介绍

面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP的功能将切面织入到主业务逻辑中。所谓交叉业务逻辑是指,通用的、与主业务逻辑无关的代码,如安全检查、事务、日志等。若不使用AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样,会使主业务逻辑变的混杂不清

添加对应的依赖

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.1.17.RELEASE</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.1</version>
    </dependency>
</dependencies>

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中一个核心思想,面向切面编程,其主要作用就是提取出公共的业务方法,对目标方法进行一个增强。其原理就是采用的代理模式。

  • 5
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值