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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://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")@Aspectpublic 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/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/contexthttps://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.*.*(..)
