1、AOP简介
面向切面编程,把遍布应用各处的功能分离出来,形成可重复使用的组件。
2、术语
1、通知
定义切面是什么,在什么时候使用。通知除了要完成工作,还要说明是在什么时候完成的。是在方法调用之前?还是之后?通知分为5种类型。
before | 在方法调用之前执行 |
after | 在方法调用之后执行,无论成功与失败 |
after-returning | 在方法执行成功之后执行 |
after-throwing | 在方法抛出异常后执行 |
around | 在方法调用之前和之后执行 |
2、连接点
应用中需要应用通知的地方。连接点是应用中可以插入切面的一个点,这个点可以是调用方法时,也可以是抛出异常时。
3、切点
在何处织入。切点可以匹配一个或者多个连接点。
4、切面
通知和切点的结合,同时完成了切面的全部功能,他是什么,在什么时候,什么地方完成了什么功能。
5、引入
允许向现有的类添加新的属性和方法。
6、织入
将切面应用到目标对象创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中。在生命周期有多个时期可以植入
(1)编译期
(2)类加载期
(3)运行期
3、编写切点
切点使用接口和实现类的全路径均可。
execution(* dao.TestService.testPlay(..))
execution:执行方法时触发
*:返回任意类型
dao.TestService:方法的全路径
testPlay():连接点
(..): 任意参数类型
4、使用XML配置AOP
1、依赖
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<!--切面依赖-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.2.15.RELEASE</version>
</dependency>
</dependencies>
2、创建接口UserDao接口和实现类
接口:
public interface UserDao {
public void play();
}
实现类:
@Repository("userDao")
public class UserDaoImpl implements UserDao{
@Override
public void play() {
System.out.println("running...");
}
}
3、创建TestService和实现类(需要被增强的方法)
接口:(对testPlay()进行增强)
public interface TestService {
public void testPlay();
}
实现类:
@Component("userService")
@Service("userService")
public class TestServiceImpl implements TestService{
//注解注入,需要配置包扫描
@Autowired
@Qualifier("userDao")
private UserDao userDao;
@Override
public void testPlay() {
System.out.println("test...");
userDao.play();
}
}
4、创建AOP类
public class AOPConfig {
//前置通知
public void playBefore(){
System.out.println("AOP befort......");
}
//后置通知
public void playAfter(){
System.out.println("AOP fater......");
}
}
5、配置applicationContext.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--扫包-->
<context:component-scan base-package="dao"/>
<!--创建Bean-->
<bean id="userDao" class="dao.UserDaoImpl"/>
<bean id="userService" class="dao.TestServiceImpl"/>
<bean id="aopConfig" class="dao.AOPConfig"/>
<aop:config>
<aop:aspect ref="aopConfig">
<!--接口和实现类均可,需要导入依赖 aspectjweaver-->
<aop:pointcut id="play" expression="execution(* dao.TestServiceImpl.testPlay(..))"/>
<!--<aop:pointcut id="play" expression="execution(* dao.TestService.testPlay(..))"/>-->
<aop:before pointcut-ref="play" method="playBefore"/>
<aop:after pointcut-ref="play" method="playAfter"/>
<!--<aop:around pointcut-ref="play" method="playBefore"/>-->
</aop:aspect>
</aop:config>
</beans>
6、测试
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
TestService service = (TestService) context.getBean("userService");
service.testPlay();
}
}
5、使用注解配置AOP(有参注入)
1、创建接口和实现类
接口:
public interface ReaderPeople {
void MyThink(String thoughts);
String getThought();
}
实现类
public class ReaderImpl implements ReaderPeople{
private String thought;
@Override
public void MyThink(String thoughts) {
System.out.println("my love");
this.thought = thoughts;
}
public String getThought(){
return thought;
}
}
2、创建增强接口和实现类
接口:
public interface ReadThough {
public void interceptThoughts(String thoughs);
public String printThoughts();
public void interceptThoughtsAfter(String thought);
}
实现类:
@Aspect //注解
public class ReadThoughImpl implements ReadThough{
private String thought;
@Pointcut(value = "execution(* AOP.ReaderImpl.*(..))")
public void pintdemo(){}
@Before(value = "pintdemo() && args(thought)") //这里不能用and
@Override
public void interceptThoughts(String thought) {
System.out.println("提前监听");
this.thought = thought;
}
@Override
public String printThoughts() {
return this.thought;
}
@After(value = "pintdemo() && args(thought)")
@Override
public void interceptThoughtsAfter(String thought) {
System.out.println("拦截之后...");
}
}
3、applicationContext.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation=
"http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--扫包-->
<context:component-scan base-package="dao"/>
<!--配置AOP注解-->
<aop:aspectj-autoproxy/>
</beans>
4、测试
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
ReaderPeople reader = (ReaderPeople) context.getBean("reader");
reader.MyThink("spring AOP");
System.out.println(reader.getThought());
}
5、当使用AOP的切点有参数时,对应的所有通知方法也必须带有对应参数
感谢小赵同学的大力支持
注:以上内容来自书籍Spring实战