Spring 中通常使用 AspectJ 来实现 AOP 操作,AspectJ 不是 Spring 的组成部分,是独立的 AOP 框架。
更多:AOP 基础
基于 XML 的 AOP
定义接口及实现
public interface UserService {
void save(int a);
void get();
void delete(int id);
}
public class UserServiceImpl implements UserService {
public void save(int a) {
System.out.println("save 方法执行");
}
public void get() {
System.out.println("get 方法执行");
int n = 1 / 0;
}
public void delete(int id) {
System.out.println("delete 方法执行");
}
}
AOP增强类
public class SpeLogger {
public void beforeOrgLogger() {
System.out.println("前置通知 Executed !");
}
public void afterReturnOrgLogger() {
System.out.println("后置通知 Executed !");
}
public void throwOrgLogger() {
System.out.println("异常通知 Executed !");
}
public void afterOrgLogger() {
System.out.println("最终通知 Executed !");
}
public Object aroundOrgLogger(ProceedingJoinPoint proceedingJoinPoint) {
Object data = null;
try {
System.out.println("前置通知");
Object[] args = proceedingJoinPoint.getArgs();
data = proceedingJoinPoint.proceed(args);
System.out.println("后置通知");
} catch (Throwable e) {
System.out.println("异常通知");
} finally {
System.out.println("最终通知");
}
return data;
}
}
加入 IOC
<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
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 接口 -->
<bean id="userService" class="cn.com.lichenghao.service.impl.UserServiceImpl"></bean>
<!-- 通知类 -->
<bean id="speLogger" class="cn.com.lichenghao.aop.SpeLogger"></bean>
<aop:config>
<!-- 切点 -->
<aop:pointcut id="logOperation" expression="execution(* cn.com.lichenghao.service.impl.*.*(..))"/>
<!-- 切面 -->
<aop:aspect ref="speLogger">
<!-- 通知类型 前置、后置、异常、最终通知-->
<!--
<aop:before method="beforeOrgLogger" pointcut-ref="logOperation"></aop:before>
<aop:after-returning method="afterReturnOrgLogger" pointcut-ref="logOperation"></aop:after-returning>
<aop:after-throwing method="throwOrgLogger" pointcut-ref="logOperation"></aop:after-throwing>
<aop:after method="afterOrgLogger" pointcut-ref="logOperation"></aop:after>
-->
<!-- 环绕通知 -->
<aop:around method="aroundOrgLogger" pointcut-ref="logOperation"></aop:around>
</aop:aspect>
</aop:config>
</beans>
测试下
public class Test {
public static void main(String[] args) {
/**
* 配置文件方式
*/
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
UserService userService = (UserService)context.getBean("userService");
userService.get();
}
}
基于注解的 AOP
定义增强类
@Component("speLogger")
@Aspect
public class SpeLogger {
@Pointcut(value = "execution(* cn.com.lichenghao.service.impl.*.*(..))")
private void pt() {
}
@Before("pt()")
public void beforeOrgLogger() {
System.out.println("前置通知 Executed !");
}
@AfterReturning("pt()")
public void afterReturnOrgLogger() {
System.out.println("后置通知 Executed !");
}
@AfterThrowing("pt()")
public void throwOrgLogger() {
System.out.println("异常通知 Executed !");
}
@After("pt()")
public void afterOrgLogger() {
System.out.println("最终通知 Executed !");
}
//@Around("pt()")
public Object aroundOrgLogger(ProceedingJoinPoint proceedingJoinPoint) {
Object data = null;
try {
System.out.println("前置通知");
Object[] args = proceedingJoinPoint.getArgs();
data = proceedingJoinPoint.proceed(args);
System.out.println("后置通知");
} catch (Throwable e) {
System.out.println("异常通知");
} finally {
System.out.println("最终通知");
}
return data;
}
}
加入IOC
application-annotation.xml
<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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 包扫描 -->
<context:component-scan base-package="cn.com.lichenghao"></context:component-scan>
<!-- 启用aspectj注解 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
测试下
public class Test {
public static void main(String[] args) {
/**
* 注解方式
*/
ApplicationContext context = new ClassPathXmlApplicationContext("application-annotation.xml");
UserService userService = (UserService) context.getBean("userService");
userService.save(1);
}
}
切入点表达式
用来表示对哪个类中的哪个方法进行增强
标准方式
访问修饰符 返回值 包名.包名.包名…类名.方法名(参数列表)
public void cn.com.lichenghao.service.impl.UserServiceImpl.get()
简化过程↓↓↓
👇
省略访问修饰符
void cn.com.lichenghao.service.impl.UserServiceImpl.get()
👇
返回值使用通配符*,表示任意返回值
* cn.com.lichenghao.service.impl.UserServiceImpl.get()
👇
包名使用通配符,代表包名,几级包名就写几个
* *.*.*.*.impl.UserServiceImpl.get()
👇
包名通配符,*..代表包以及子包
* *..service.impl.UserServiceImpl.get()
👇
类名和方法名可以使用通配符*
* *..service.impl.*.get()
* *..service.impl.*.*()
👇
参数列表可以写(基本类型直接写例如:int,引用类型写包全路径例如:java.lang.String)
👇
参数类型可以使用通配符*,前提是必须有参数
* *..service.impl.*.*(*)
👇
参数类型可以使用..表示参数可以是任意类型
* *..service.impl.*.*(..)
全通配
全通配方式:
* *..*.*(..)
需要注意,如果这样配置,所有类的都满足这种方式,一般都不会这样配置
通常写法
业务类下的所有方法
* cn.com.lichenghao.service.impl.*.*(..)