目录
能够在不修改已有代码的情况下,批量修改接口的实现。通过在具体方法的前后选择性地插入代码。
1.先测试一个普通Ioc
1.1.创建接口和类
package com.example.aopdemo.domain;
public interface Person {
void speak();
}
package com.example.aopdemo.domain;
import org.springframework.stereotype.Component;
@Component
public class Boy implements Person {
@Override
public void speak() {
System.out.println("I'm boy");
}
}
package com.example.aopdemo.domain;
import org.springframework.stereotype.Component;
@Component
public class Girl implements Person{
@Override
public void speak() {
System.out.println("I'm a girl");
}
}
1.2.配置文件
package com.example.aopdemo.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan(value = {"com.example.aopdemo.domain"})
public class PersonConfig {
}
1.3.测试
@SpringBootTest
class AopdemoApplicationTests {
@Test
void contextLoads() {
var context=new AnnotationConfigApplicationContext(PersonConfig.class);
Boy boy=context.getBean("boy", Boy.class);
Girl girl=context.getBean("girl",Girl.class);
boy.speak();
girl.speak();
}
}
//I'm boy
//I'm a girl
2.加入AOP
如果要在每个speak方法前,加入一句“hello”,需要修改多处代码。此时可以用到aop,只需添加一个方法,用以说明在执行speak方法前还需执行另一个方法。
2.1.添加依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>3.0.2</version>
</dependency>
2.2.添加aop方法
*代表返回类型任意;..代表参数类型任意
@Component
@Aspect
public class PersonRevise {
@Before("execution(* com.example.aopdemo.domain.Person.speak(..))")
public void greet(){
System.out.println("Hello!");
}
}
2.3.在ioc配置文件中加入允许aspect的注释
默认是false。如果aop文件不在domain的同一个文件下,需要重新扫描。
@Configuration
@ComponentScan(value = {"com.example.aopdemo.domain"})
@ComponentScan(value = {"com.example.aopdemo.aop"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class PersonConfig {
}
3.其他插入
除了before,还有after,round等,为了避免重复的复制路径,可以先定义一个pointcut。
@Component
@Aspect
public class PersonRevise {
@Pointcut("execution(* com.example.aopdemo.domain.Person.speak(..))")
public void speakPoint(){}
@Before("speakPoint()")
public void greet(){
System.out.println("Hello!");
}
@After("speakPoint()")
public void bye(){
System.out.println("goodbye");
}
@Around(value = "speakPoint()")
public void round(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("start");
joinPoint.proceed();
System.out.println("end");
}
@AfterThrowing(pointcut = "speakPoint()",throwing = "e")
public void error(Exception e){
e.printStackTrace();
}
}
&& ,|| ,!可以用来筛选多个条件
around可以实现更复杂的流程
@Pointcut("execution(void com.example.aopdemo.domain.Person.tellAge(int)) &&bean(girl) &&args(age)")
public void girPoint(int age){}
@Around("girPoint(age)")
public void ys(ProceedingJoinPoint point,int age) {
try{
point.proceed();
if (age>=18)
System.out.println("I'm a adult");
else
System.out.println("I'm a child");
} catch (Throwable throwable) {
throwable.printStackTrace();
}
}