spring --Aop
AOP核心思想:
在不改变源码的情况下,实现对原有功能的动态增强
Spring AOP就是将公共的业务(日志,安全等)和领域业务解合起来,当执行领域业务时,把公共业务插进来。
可以实现公共业务的复用,领域业务更纯粹,让开发人员专注业务开发,其本质还是动态代理。
这张图更清楚些,(扒了狂神的公众号,推荐微信搜索“狂神说”,太有用了)
AOP在Spring中的作用
- 提供声明式事务;
- 允许用户自定义切面
AOP 术语
- 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
- 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
- 切点(PointCut): 可以插入增强处理的连接点。
- 切面(Aspect): 切面是通知和切点的结合。
- 引入(Introduction):引入允许我们向现有的类添加新的方法或者属性。
- 织入(Weaving): 将增强处理添加到目标对象中,并创建一个被增强的对象,这个过程就是织入。
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
使用AOP织入,导入依赖包
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.6</version> </dependency>
第一种 使用Spring API 实现
业务接口和实现类
public interface UserService { void add(); void delete(); void update(); void query(); } ==================== public class UserServiceImpl implements UserService { @Override public void add() { System.out.println("增加了一个用户"); } @Override public void delete() { System.out.println("删除了一个用户"); } @Override public void update() { System.out.println("修改了一个用户"); } @Override public void query() { System.out.println("查询了一个用户"); } }
增强类,前置增强和后置增强
public class Log implements MethodBeforeAdvice { @Override //method 要执行的目标对象的方法 //objects :参数 agrs //Object o :target 目标对象 public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println(o.getClass().getName()+"的 "+method.getName()+"方法" ); } } public class AfterLog implements AfterReturningAdvice { @Override //Object o 返回值 //Object o1 target public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { System.out.println("执行了"+method.getName()+"方法,返回结果为:"+o); } }
Spring xml中注册,并实现aop切入,注意导入约束
<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="com.wpz.aop.service.UserServiceImpl"/> <bean id ="log" class="com.wpz.aop.log.Log"/> <bean id ="afterLog" class="com.wpz.aop.log.AfterLog"/> <!-- 配置aop 需要导入约束--> <aop:config> <!-- 切入点 expression配置要执行的方法--> <aop:pointcut id="pointcut" expression="execution(* com.wpz.aop.service.UserServiceImpl.*(..))"/> <!-- 执行环绕增加 advice-ref执行的方法 pointcut-ref切入点 --> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config>
测试类
public void test(){ ApplicationContext context =new ClassPathXmlApplicationContext("ApplicationContext.xml"); UserService userService = (UserService) context.getBean("userService"); userService.add(); }
第二种 使用自定义类 配置实现
自定义切面类
public class DiyPointCut { public void before(){ System.out.println("方法执行前==============="); } public void after (){ System.out.println("方法执行后================"); } }
配置文件
<!-- 第二种-->
<!-- 注册bean-->
<bean id="diy" class="com.wpz.aop.diy.DiyPointCut"></bean>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="diyPointCut" expression="execution(* com.wpz.aop.service.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="diyPointCut"/>
<aop:after method="after" pointcut-ref="diyPointCut"/>
</aop:aspect>
</aop:config>
测试类同上
第三种 使用自定义类 注解实现
import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; @Aspect public class AnnotitionPointCut { @Before("execution(* com.wpz.aop.service.UserServiceImpl.*(..))") public void before(){ System.out.println("方法执行前==============="); } @After("execution(* com.wpz.aop.service.UserServiceImpl.*(..))") public void after (){ System.out.println("方法执行后================"); } @Around("execution(* com.wpz.aop.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕前"); System.out.println("qianming==="+jp.getSignature()); Object obj = jp.proceed(); System.out.println("环绕后"); System.out.println("obj======"+obj); } }
配置文件,需要增加支持注解的配置
<!-- 第三种--> <bean id="annotation" class="com.wpz.aop.annotition.AnnotitionPointCut"/> <aop:aspectj-autoproxy proxy-target-class="false"/>
proxy-target-class属性:缺省值为false,表示使用jdk动态代理织入,如果目标类没有声明接口,则自动使用CGlib动态代理。
关于表达式的使用:execution(* * * * * )
<aop:pointcut id="diyPointCut" expression="execution(* com.wpz.aop.service.UserServiceImpl.*(..))"/>
“aop:pointcut”标签中"expression"的写法规则如下:
execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?)
ret-type-pattern,name-pattern(param-pattern)是必须的.
ret-type-pattern:标识方法的返回值,需要使用全路径的类名如java.lang.String,也可以为*表示任何返回值;
name-pattern:指定方法名,*代表所有,例如set*,代表以set开头的所有方法.
param-pattern:指定方法参数(声明的类型),(..)代表所有参数,(*)代表一个参数,(*,String)代表第一个参数为任何值,第二个为String类型.表达式例子如下:
任意公共方法的执行:
execution(public * *(..))
任何一个以“set”开始的方法的执行:
execution(* set*(..))
AccountService 接口的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
定义在service包里的任意方法的执行:
execution(* com.xyz.service.*.*(..))
定义在service包和所有子包里的任意类的任意方法的执行:
execution(* com.xyz.service..*.*(..))
定义在pointcutexp包和所有子包里的JoinPointObjP2类的任意方法的执行:
execution(* com.test.spring.aop.pointcutexp..JoinPointObjP2.*(..))")在多个表达式之间使用 ||,or表示 或,使用 &&,and表示 与,!表示 非.例如:
<aop:config>
<aop:pointcut id="pointcut" expression="(execution(* com.ccboy.dao..*.find*(..))) or (execution(* com.ccboy.dao..*.query*(..)))"/>
<aop:advisor advice-ref="jdbcInterceptor" pointcut-ref="pointcut" />
</aop:config>
表达式上车:https://www.cnblogs.com/langren1992/p/9705231.html