Spring(五)AOP

目录

1.简介

2.基于xml的AOP

2.1入门

2.2.xml配置详解

2.2.1切点表达式

2.2.2AOP的四大通知

2.2.3切点表达式的抽取

2.2.4环绕通知

3.基于注解的AOP

3.1开启AOP注解的支持

3.2声明通知类

3.3使用配置类代替applicationContext


1.简介

        Aspect Oriented Programming,面向切面编程,它是一种思想。目的就是在不修改源代码的情况下对原有功能进行增强。

        SpringAOP是对AOP思想的一种实现,底层同时支持jdk动态代理和cglib动态代理。

Spring会根据被代理的类是否有接口自动选择代理方式:

  • 如果有接口,就采用jdk动态代理(也可以强制使用cglib)

  • 没有接口就采用cglib的方式

SpringAOP相关术语

Target:目标对象  

                就是需要增强的对象 
   

JoinPoint:连接点
                目标对象中的所有方法

Pointcut:切点
                目标对象中需要增强的方法
   

Advice:增强(通知)
                增强类或通知类,增强目标对象时使用的类
                增强方法或通知方法,增强目标对象时使用的方法

Weaving:织入
                动词,将切点和增强方法结合起来的这个动作

Aspect:切面
                将切点和增强方法织入后就得到了切面。

                切点+增强方法=切面

Proxy:代理对象  java的术语
 

2.基于xml的AOP

2.1入门

pom.xml

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
    </dependencies>

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <aop:config>
        <aop:aspect ref="myAccountAdvice">
            <aop:before method="myBefore" pointcut="execution(public void com.study.service.impl.AccountServiceImpl.transfer())"/>
        </aop:aspect>
    </aop:config>

</beans>

测试类

@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountServiceImplTest {

    @Autowired
    AccountService accountService;

    @Test
    public void transfer() {
        accountService.transfer();
        System.out.println("----------");
        accountService.transfer("jiujiu");
        System.out.println("----------");
        accountService.transfer("jiujiu","lili",100D);
        System.out.println("----------");
        accountService.findAll();
    }
}

service接口

public interface AccountService {

    void transfer();
    void transfer(String name);
    void transfer(String outName,String inName,Double money);
    void findAll();
}

service实现类

public class AccountServiceImpl implements AccountService {
    @Override
    public void transfer() {
        System.out.println("执行了无参transfer方法");
    }

    @Override
    public void transfer(String name) {
        System.out.println("执行了一个参数的transfer方法");
    }

    @Override
    public void transfer(String outName, String inName, Double money) {
        System.out.println("执行了三个参数的transfer方法");
    }

    @Override
    public void findAll() {
        System.out.println("执行了findAll方法");
    }
}

通知类(增强类)

public class MyAccountAdvice {

    public void myBefore(){
        System.out.println("执行了前置方法");
    }

    public void myAfterReturnning(){
        System.out.println("执行了后置方法");
    }

    public void myAfterThrowing(){
        System.out.println("执行了异常方法");
    }

    public void myAfter(){
        System.out.println("执行了最终方法");
    }
}

输出结果

执行了前置方法
执行了无参transfer方法
----------
执行了一个参数的transfer方法
----------
执行了三个参数的transfer方法
----------
执行了findAll方法

        我们发现,在applicationConetext.xml中我们对于切点transfer织入了前置方法myBefore,只有午餐的transfer方法生效了,有参的transfer和findAll方法并没有生效,说明在aop配置时只对配置的方法生效,重载方法无效。

2.2.xml配置详解

2.2.1切点表达式

表达式语法:

execution([修饰符] 返回值类型 包名.类名.方法名(参数))

* 表示占位符

.. 表示数量可变

修饰符可以省略

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">
            <!--对于方法增强,只增强了无参的transfer-->
            <!--<aop:before method="myBefore" pointcut="execution(public void com.study.service.impl.AccountServiceImpl.transfer())"/>-->

            <!--修饰符可以省略-->
            <aop:before method="myBefore" pointcut="execution(public void com.study.service.impl.AccountServiceImpl.transfer())"/>


        </aop:aspect>
    </aop:config>

</beans>
执行了前置方法
执行了无参transfer方法
----------
执行了一个参数的transfer方法
----------
执行了三个参数的transfer方法
----------
执行了findAll方法

一个参数

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">

            <!--参数位置的 * 表示参数的占位-->
            <!--对一个参数的transfer方法进行增强,但是对无参方法失效了-->
            <aop:before method="myBefore" pointcut="execution(public void com.study.service.impl.AccountServiceImpl.transfer(*))"/>
            
        </aop:aspect>
    </aop:config>

</beans>
执行了无参transfer方法
----------
执行了前置方法
执行了一个参数的transfer方法
----------
执行了三个参数的transfer方法
----------
执行了findAll方法

三个参数

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">

            <!--对三个参数的transfer方法进行了增强,但是对无参\一个参数的方法失效了-->
            <aop:before method="myBefore" pointcut="execution(public void com.study.service.impl.AccountServiceImpl.transfer(*,*,*))"/>


        </aop:aspect>
    </aop:config>

</beans>
执行了无参transfer方法
----------
执行了一个参数的transfer方法
----------
执行了前置方法
执行了三个参数的transfer方法
----------
执行了findAll方法

所有参数

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">


            <!--参数的位置中使用 .. 表示参数数量可变-->
            <aop:before method="myBefore" pointcut="execution(public void com.study.service.impl.AccountServiceImpl.transfer(..))"/>



        </aop:aspect>
    </aop:config>

</beans>
执行了前置方法
执行了无参transfer方法
----------
执行了前置方法
执行了一个参数的transfer方法
----------
执行了前置方法
执行了三个参数的transfer方法
----------
执行了findAll方法

所有方法

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">


            <!--增强所有方法-->
            <aop:before method="myBefore" pointcut="execution(public void com.study.service.impl.AccountServiceImpl.*(..))"/>

        </aop:aspect>
    </aop:config>

</beans>
执行了前置方法
执行了无参transfer方法
----------
执行了前置方法
执行了一个参数的transfer方法
----------
执行了前置方法
执行了三个参数的transfer方法
----------
执行了前置方法
执行了findAll方法

同一个包下所有类所有方法

测试类

@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountServiceImplTest {

    @Resource
    AccountService accountService;

    @Resource
    AccountService accountServiceCopy;

    @Test
    public void transfer() {
        accountService.transfer();
        System.out.println("----------");
        accountService.transfer("jiujiu");
        System.out.println("----------");
        accountService.transfer("jiujiu","lili",100D);
        System.out.println("----------");
        accountService.findAll();
        System.out.println("----------");
        accountServiceCopy.transfer();
        System.out.println("----------");
        accountServiceCopy.transfer("jiujiu");
        System.out.println("----------");
        accountServiceCopy.transfer("jiujiu","lili",100D);
        System.out.println("----------");
        accountServiceCopy.findAll();
    }
}

coty类

public class AccountServiceImplCopy implements AccountService {
    @Override
    public void transfer() {
        System.out.println("copy执行了无参transfer方法");
    }

    @Override
    public void transfer(String name) {
        System.out.println("copy执行了一个参数的transfer方法");
    }

    @Override
    public void transfer(String outName, String inName, Double money) {
        System.out.println("copy执行了三个参数的transfer方法");
    }

    @Override
    public void findAll() {
        System.out.println("copy执行了findAll方法");
    }
}

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="accountServiceCopy" class="com.study.service.impl.AccountServiceImplCopy"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">
            

            <!--增强同一个包下的所有类的所有方法-->
            <aop:before method="myBefore" pointcut="execution(public void com.study.service.impl.*.*(..))"/>

        </aop:aspect>
    </aop:config>

</beans>

输出

执行了前置方法
执行了无参transfer方法
----------
执行了前置方法
执行了一个参数的transfer方法
----------
执行了前置方法
执行了三个参数的transfer方法
----------
执行了前置方法
执行了findAll方法
----------
执行了前置方法
copy执行了无参transfer方法
----------
执行了前置方法
copy执行了一个参数的transfer方法
----------
执行了前置方法
copy执行了三个参数的transfer方法
----------
执行了前置方法
copy执行了findAll方法

增强study包下所有包中的所有方法

company接口

public interface CompanyService {

    void findAll();
}

company实现类

public class CompanyServiceImpl implements CompanyService {
    @Override
    public void findAll() {
        System.out.println("执行了CompanyServiceImpl的findAll方法");
    }
}

测试类

@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountServiceImplTest {

    @Resource
    AccountService accountService;

    @Resource
    AccountService accountServiceCopy;

    @Autowired
    CompanyService companyService;

    @Test
    public void transfer() {
        accountService.transfer();
        System.out.println("----------");
        accountService.transfer("jiujiu");
        System.out.println("----------");
        accountService.transfer("jiujiu","lili",100D);
        System.out.println("----------");
        accountService.findAll();
        System.out.println("----------");
        accountServiceCopy.transfer();
        System.out.println("----------");
        accountServiceCopy.transfer("jiujiu");
        System.out.println("----------");
        accountServiceCopy.transfer("jiujiu","lili",100D);
        System.out.println("----------");
        accountServiceCopy.findAll();

        System.out.println("----------");
        companyService.findAll();
    }
}

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="accountServiceCopy" class="com.study.service.impl.AccountServiceImplCopy"/>
    <bean id="companyService" class="com.study.service.company.impl.CompanyServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">
            

            <!--增强study下所有包中所有类的所有方法-->
            <aop:before method="myBefore" pointcut="execution(public void com.study..*.*(..))"/>

        </aop:aspect>
    </aop:config>

</beans>

输出

执行了前置方法
执行了无参transfer方法
----------
执行了前置方法
执行了一个参数的transfer方法
----------
执行了前置方法
执行了三个参数的transfer方法
----------
执行了前置方法
执行了findAll方法
----------
执行了前置方法
copy执行了无参transfer方法
----------
执行了前置方法
copy执行了一个参数的transfer方法
----------
执行了前置方法
copy执行了三个参数的transfer方法
----------
执行了前置方法
copy执行了findAll方法
----------
执行了前置方法
执行了CompanyServiceImpl的findAll方法

一般只将一层进行增强,比如service层

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="accountServiceCopy" class="com.study.service.impl.AccountServiceImplCopy"/>
    <bean id="companyService" class="com.study.service.company.impl.CompanyServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">

            <!--增强service层-->
            <aop:before method="myBefore" pointcut="execution(public void com.study.service..*.*(..))"/>
            
        </aop:aspect>
    </aop:config>

</beans>

所有返回值

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="accountServiceCopy" class="com.study.service.impl.AccountServiceImplCopy"/>
    <bean id="companyService" class="com.study.service.company.impl.CompanyServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">

            <!--所有返回值进行增强-->
            <aop:before method="myBefore" pointcut="execution(* com.study.service..*.*(..))"/>

        </aop:aspect>
    </aop:config>

</beans>

2.2.2AOP的四大通知

四大通知分别是:

before:前置通知,切点运行之前执行。

after-returning:后置通知,切点正常运行之后执行。

after-throwing:异常通知,切点异常后执行。

after:最终通知,无论是否异常,切点运行后执行。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="accountServiceCopy" class="com.study.service.impl.AccountServiceImplCopy"/>
    <bean id="companyService" class="com.study.service.company.impl.CompanyServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">

            <!--配置前置通知-->
            <aop:before method="myBefore" pointcut="execution(* com.study.service..*.*(..))"/>
            <!--配置后置通知-->
            <aop:after-returning method="myAfterReturnning" pointcut="execution(* com.study.service..*.*(..))"/>
            <!--配置异常通知-->
            <aop:after-throwing method="myAfterThrowing" pointcut="execution(* com.study.service..*.*(..))"/>
            <!--配置最终通知-->
            <aop:after method="myAfter" pointcut="execution(* com.study.service..*.*(..))"/>
        </aop:aspect>
    </aop:config>

</beans>

        四大通知在xml中的顺序是有要求的,最终通知要写到最后。

2.2.3切点表达式的抽取

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="accountServiceCopy" class="com.study.service.impl.AccountServiceImplCopy"/>
    <bean id="companyService" class="com.study.service.company.impl.CompanyServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">

            <aop:pointcut id="myPointcut" expression="execution(* com.study.service..*.*(..))"/>

            <!--配置前置通知-->
            <aop:before method="myBefore" pointcut-ref="myPointcut"/>
            <!--配置后置通知-->
            <aop:after-returning method="myAfterReturnning" pointcut-ref="myPointcut"/>
            <!--配置异常通知-->
            <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointcut"/>
            <!--配置最终通知-->
            <aop:after method="myAfter" pointcut-ref="myPointcut"/>
        </aop:aspect>
    </aop:config>

</beans>

2.2.4环绕通知

        spring不推荐开发者使用四大通知,而是推荐我们使用环绕通知,所以四大通知的顺序问题没有解决。

使用环绕通知需要在通知类中额外书写一个环绕方法

public class MyAccountAdvice {

    public void myBefore(){
        System.out.println("执行了前置方法");
    }

    public void myAfterReturnning(){
        System.out.println("执行了后置方法");
    }

    public void myAfterThrowing(){
        System.out.println("执行了异常方法");
    }
    
    public void myAfter(){
        System.out.println("执行了最终方法");
    }
    
    public void myAround(ProceedingJoinPoint pjp){
        try {
            myBefore();
            pjp.proceed();
            myAfterReturnning();
        } catch (Throwable throwable) {
            myAfterThrowing();
            throwable.printStackTrace();
        } finally {
            myAfter();
        }
    }
}

对应的applicationContext.xml也需要修改

无需书写四大通知,而是直接用环绕通知代替

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd">


    <bean id="accountService" class="com.study.service.impl.AccountServiceImpl"/>
    <bean id="accountServiceCopy" class="com.study.service.impl.AccountServiceImplCopy"/>
    <bean id="companyService" class="com.study.service.company.impl.CompanyServiceImpl"/>
    <bean id="myAccountAdvice" class="com.study.advice.MyAccountAdvice"/>

    <!--aop的配置-->
    <aop:config>
        <!--配置切面,指定这个切面所用到的通知类-->
        <aop:aspect ref="myAccountAdvice">

            <aop:around method="myAround" pointcut="execution(* com.study.service..*.*(..))"/>

        </aop:aspect>
    </aop:config>

</beans>

3.基于注解的AOP

3.1开启AOP注解的支持

<aop:aspectj-autoproxy/>

3.2声明通知类

@Aspect

@Before(切点表达式)

@AfterReturning(切点表达式)

@AfterThrowing(切点表达式)

@After(切点表达式)

@Pointcut(切点表达式)        随便写个方法名,添加注解,抽取切点表达式

applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
		http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
		http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.study"/>

    <!--开启aop的注解支持-->
    <aop:aspectj-autoproxy/>


</beans>

通知类(四大通知有顺序问题,所以使用环绕通知)

@Component
@Aspect
public class MyAccountAdvice {

    @Pointcut("execution(* com.study.service..*.*(..))")
    public void myPointcut(){}

//    @Before("MyAccountAdvice.myPointcut()")
    public void myBefore(){
        System.out.println("执行了前置方法");
    }
//    @AfterReturning("MyAccountAdvice.myPointcut()")
    public void myAfterReturnning(){
        System.out.println("执行了后置方法");
    }
//    @AfterThrowing("MyAccountAdvice.myPointcut()")
    public void myAfterThrowing(){
        System.out.println("执行了异常方法");
    }
//    @After(("MyAccountAdvice.myPointcut()"))
    public void myAfter(){
        System.out.println("执行了最终方法");
    }

    @Around("MyAccountAdvice.myPointcut()")
    public void myAround(ProceedingJoinPoint pjp){
        try {
            myBefore();
            pjp.proceed();
            myAfterReturnning();
        } catch (Throwable throwable) {
            myAfterThrowing();
            throwable.printStackTrace();
        } finally {
            myAfter();
        }
    }
}

测试类

@RunWith(SpringRunner.class)
@ContextConfiguration(locations = "classpath:applicationContext.xml")
public class AccountServiceImplTest {

    @Autowired
    AccountService accountService;


    @Test
    public void transfer() {
        accountService.transfer();

    }
}

3.3使用配置类代替applicationContext

添加配置类、删除applicationContext.xml中的内容

@Configuration
@ComponentScan(value = "com.study")
@EnableAspectJAutoProxy
public class SpringConfig {
}

测试类

@RunWith(SpringRunner.class)
//@ContextConfiguration(locations = "classpath:applicationContext.xml")
@ContextConfiguration(classes = SpringConfig.class)
public class AccountServiceImplTest {

    @Autowired
    AccountService accountService;


    @Test
    public void transfer() {
        accountService.transfer();

    }
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值