目录
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();
}
}