Related terms
Target
Proxy (Proxy Object)
Advice (notification/enhancement)
Joinpoint (connection point): a method that can be enhanced is called a connection point
Pointcut (pointcut): the method that is actually enhanced is called the pointcut
Aspect: point of contact + notification
Weaving (weaving): the process of combining pointcut + notification to generate agent
Development issues
▍What needs to be written/configured?
- Write the target class and target method
- Write aspect classes and enhancement methods
- Configure the weaving relationship and tell Spring which pointcuts are combined with which notifications
▍ Please briefly SpringAOP the process?
- Spring will automatically monitor the execution of pointcut methods
- Once the pointcut method is executed, the proxy mechanism is immediately triggered, that is, the proxy object of the target object where the target method is dynamically created
- The method of notifying the corresponding position of the woven into the proxy object, composing the complete code logic and running
▍ What kind of dynamic proxy mode will be used at the bottom of AOP?
- Spring will automatically decide which dynamic proxy method to use (JDK/cglib) according to whether the target class implements the interface
▍What maven coordinates need to be imported?
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.4</version>
</dependency>
<!-- spring拥有自己的aop包,但实际上使用的是更加优秀的aspectj提供的aop包 -->
Based on XML (code)
① Write the target class and target method
目标类接口 ----------------------------------------------------------------------------------
public interface TargetInterface {
public void sayHi();
}
目标类 -------------------------------------------------------------------------------------
public class Target implements TargetInterface {
public void sayHi() {
System.out.println("Hello >_<!");
}
}
② Compile aspect classes and enhancement methods
切面类 -------------------------------------------------------------------------------------
public class MyAspect {
public void enhanceBefore() {
System.out.println("前置增强...");
}
public void enhanceAfterReturning() {
System.out.println("后置增强...");
}
public Object enhanceAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前增强...");
Object obj = joinPoint.proceed();
System.out.println("环绕后增强...");
return obj;
}
public void enhanceAfterThrowing() {
System.out.println("异常抛出增强...");
}
public void anhanceAfter() {
System.out.println("最终增强...");
}
}
③ Configuration file (introduce the aop namespace, put the object into the container, and tell Spring to weave the relationship)
<?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: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/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 目标对象 -->
<bean id="target" class="aop.Target"></bean>
<!-- 切面对象 -->
<bean id="aspect" class="aop.MyAspect"></bean>
<!-- 配置织入关系 -->
<aop:config>
<!-- 声明切面 (切面=切点+通知) -->
<aop:aspect ref="aspect">
<aop:before method="enhanceBefore" pointcut="execution(public void aop.Target.sayHi())" />
<aop:after-returning method="enhanceAfterReturning" pointcut="execution(public void aop.Target.sayHi())" />
<aop:around method="enhanceAround" pointcut="execution(public void aop.Target.sayHi())" />
<aop:after-throwing method="enhanceAfterThrowing" pointcut="execution(public void aop.Target.sayHi())" />
<aop:after method="anhanceAfter" pointcut="execution(public void aop.Target.sayHi())" />
</aop:aspect>
</aop:config>
</beans>
④ Turn on component scanning and AOP automatic proxy ( it's easy to forget >_< )
<!-- 开启组件扫描 -->
<context:component-scan base-package="XXX" />
<!-- AOP自动代理 -->
<aop:aspectj-autoproxy />
⑤ Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
@Autowired
private TargetInterface target;
@Test
public void test1() {
target.sayHi();
}
}
Based on XML (detailed explanation)
1) Cut point expression
格式:
execution([修饰符] 返回值类型 包名.类名.方法名(参数))
细节:
1. 访问修饰符(public/private)可以省略
2. 在任意位置可使用通配符(*)
3. 单点(.)表示当前包下的所有类,双点(..)表示当前包及其子包下的所有类
4. 参数使用双点(..)表示任意参数
示例:
execution(public void com.samarua.dao.UserDaoImpl.addUser(int))
// 匹配UserDaoImpl类中的公共的、返回为空的、参数为int的、UserDaoImpl类的addUser方法
execution( * com.samarua.dao.UserDaoImpl.*(..))
// 匹配UserDaoImpl类中的所有方法
execution(* com.samarua.dao..*.*())
// 匹配dao包及其子包下的所有类的所有无参的方法
2) Type of notification
Advance notice | before |
Post notification | after-returning |
Surround notification | around |
Exception thrown notification | after-throwing |
Final notice | after |
3) Extraction of cut-point expression
<!-- 就是给一个切点表达式起一个名字,配合使用pointcut-ref,从而避免反复写相同的表达式 -->
<aop:config>
<aop:aspect ref="aspect">
<aop:pointcut id="myPiontcut" expression="execution(public void aop.Target.sayHi())"/>
<aop:before method="enhanceBefore" pointcut-ref="myPiontcut" />
<aop:after-returning method="enhanceAfterReturning" pointcut-ref="myPiontcut" />
<aop:around method="enhanceAround" pointcut-ref="myPiontcut" />
<aop:after-throwing method="enhanceAfterThrowing" pointcut-ref="myPiontcut" />
<aop:after method="anhanceAfter" pointcut-ref="myPiontcut" />
</aop:aspect>
</aop:config>
Based on annotations (code)
① Write the target class and target method
@Component("target") // 目标对象放入Spring容器
...
② Compile the aspect classes and enhancement methods (the configuration of the weaving relationship was carried out at the same time)
@Component("aspect") // 切面对象放入Spring容器
@Aspect // 告诉Spring这是一个切面类(一定不要忘记这个细节>_<!!!)
public class MyAspect {
@Before("execution(* com.samarua.aop.*.*(..))")
public void enhanceBefore() {
System.out.println("前置增强...");
}
@AfterReturning("execution(* com.samarua.aop.*.*(..))")
public void enhanceAfterReturning() {
System.out.println("后置增强...");
}
@Around("execution(* com.samarua.aop.*.*(..))")
public Object enhanceAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前增强...");
Object obj = joinPoint.proceed();
System.out.println("环绕后增强...");
return obj;
}
@AfterThrowing("execution(* com.samarua.aop.*.*(..))")
public void enhanceAfterThrowing() {
System.out.println("异常抛出增强...");
}
@After("execution(* com.samarua.aop.*.*(..))")
public void anhanceAfter() {
System.out.println("最终增强...");
}
}
Based on annotations (detailed explanation)
1) Cut point expression
2) Type of notification
2) Extraction of cut-point expression
@Component("aspect")
@Aspect
public class MyAspect {
// 随便写一个空的方法作为依托,注解上切点表达式,之后直接使用该方法名即可替代表达式
@Pointcut("execution(* anno.*.*(..))")
public void myPointcut() {
}
@Before("myPointcut()")
public void enhanceBefore() {
System.out.println("前置增强...");
}
@AfterReturning("myPointcut()")
public void enhanceAfterReturning() {
System.out.println("后置增强...");
}
}