面向切面编程#
约 183 个字 8 行代码 预计阅读时间 4 分钟
名词解释#
连接点(JoinPoint)
:程序执行过程中,可以织入切面的位置
。比如方法执行前后或异常抛出之后。切点(Pointcut)
:我们配置的满足条件的目标方法
。通知(Advice)
:具体增强的方法
。切面(Aspect)
:切点
+通知
织入(Weaving)
:把通知应用到目标对象上的过程。代理对象(proxy)
:目标对象被织入后产生的新对象目标对象(Target)
:被织入的对象
AspectJ XML方式开发#
目标对象:
Java
package com.luguosong.xml;
import org.springframework.stereotype.Component;
/**
* @author luguosong
*/
public class UserServiceImpl {
public void addUser() {
System.out.println("添加用户");
}
public void deleteUser() {
System.out.println("删除用户");
//模拟异常
int i = 1 / 0;
}
public void updateUser() {
System.out.println("更新用户");
}
}
切面类:
Java
package com.luguosong.xml;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
/**
* @author luguosong
*/
public class UserAspect {
//前置通知
public void before() {
System.out.println("前置通知");
}
//后置通知
public void afterReturning() {
System.out.println("后置通知");
}
/*
* 环绕通知
*
* ❗如果发生异常,不会执行 环绕后置通知
* */
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前置通知");
Object o = joinPoint.proceed();
System.out.println("环绕后置通知");
return o;
}
//异常通知
public void afterThrowing() {
System.out.println("异常通知");
}
//最终通知
public void after(){
System.out.println("最终通知");
}
}
Spring配置文件:
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 http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.luguosong.xml.UserServiceImpl"/>
<bean id="userAspect" class="com.luguosong.xml.UserAspect"/>
<!--aop配置-->
<aop:config>
<!--配置切点表达式-->
<aop:pointcut id="myPointCut" expression="execution(* com.luguosong.xml.UserServiceImpl.*(..))"/>
<!--配置切面-->
<aop:aspect ref="userAspect">
<aop:before method="before" pointcut-ref="myPointCut"/>
<aop:after-returning method="afterReturning" pointcut-ref="myPointCut"/>
<aop:around method="around" pointcut-ref="myPointCut"/>
<aop:after method="after" pointcut-ref="myPointCut"/>
<aop:after-throwing method="afterThrowing" pointcut-ref="myPointCut"/>
</aop:aspect>
</aop:config>
</beans>
测试:
Java
package com.luguosong.xml;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author luguosong
*/
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("aspect.xml");
UserServiceImpl userService = context.getBean("userService",UserServiceImpl.class);
userService.addUser();
}
}
AspectJ注解方式开发🔥#
目标对象:
Java
package com.luguosong.anno;
import org.springframework.stereotype.Component;
/**
* @author luguosong
*/
@Component("userService")
public class UserServiceImpl {
public void addUser() {
System.out.println("添加用户");
}
public void deleteUser() {
System.out.println("删除用户");
//模拟异常
int i = 1 / 0;
}
public void updateUser() {
System.out.println("更新用户");
}
}
Spring配置类,配置组件扫描和启用基于AspectJ的自动代理
:
Java
package com.luguosong.anno;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
/**
* 注解@EnableAspectJAutoProxy表示开启自动代理
* @author luguosong
*/
@Configuration
@ComponentScan({"com.luguosong.anno"})
@EnableAspectJAutoProxy
public class SpringConfig {
}
切面类:
Java
package com.luguosong.anno;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
/**
* 切面
*
* 注解@Order控制多个切面的执行顺序
* @author luguosong
*/
@Component
@Aspect
@Order(3)
public class UserAspect {
/*
* 通用切点表达式
* */
@Pointcut("execution(* com.luguosong.anno.UserServiceImpl.*(..))")
public void pointcut() {
}
//前置通知
@Before("execution(* com.luguosong.anno.UserServiceImpl.*(..))")
public void before() {
System.out.println("前置通知");
}
//后置通知
@AfterReturning("pointcut()")
public void afterReturning() {
System.out.println("后置通知");
}
/*
* 环绕通知
*
* ❗如果发生异常,不会执行 环绕后置通知
* */
@Around("pointcut()")
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前置通知");
Object o = joinPoint.proceed();
System.out.println("环绕后置通知");
return o;
}
//异常通知
@AfterThrowing("pointcut()")
public void afterThrowing() {
System.out.println("异常通知");
}
//最终通知
@After("pointcut()")
public void after(){
System.out.println("最终通知");
}
}
测试:
Java
package com.luguosong.anno;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author luguosong
*/
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserServiceImpl userService = context.getBean("userService", UserServiceImpl.class);
userService.addUser();
userService.deleteUser();
}
}