AOP
不改变原有的业务,增加功能
AOP在Spring中的作用
- 横切关注点:跨越应用程序多个模块的方法或功能,于我们业务逻辑无关,但需要关注的部分
- 切面(aspect):横切关注点被模块化的特殊对象,是一个类
- 通知(Adivce):切面必须要完成的工作,类中的一个方法
- 目标(Target):被通知的对象
- 代理(Proxy):向目标对象应用通知后创建的对象
- 切入点(PointCut):切面通知 执行的“地点”的定义
- 连接点(JointPoint):于切入点匹配的执行点
SpringAOP中,通过Advice定义横切逻辑,支持五种类型的的advice
AOP不改变原有代码的情况下,去增加新的功能
使用Spring实现AOP
使用Spring的API接口
-
导入包
-
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.5</version> </dependency>
-
-
添加applicationContext.xml配置支持
-
xmlns:aop="http://www.springframework.org/schema/aop" http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd
-
-
找到对应的接口和实现类,实现类就是被代理对象
-
public interface UserService { public void add(); public void delete(); public void update(); public void select(); }
-
public class UserServiceImpl implements UserService{ public void add() { System.out.println("add"); } public void delete() { System.out.println("delete"); } public void update() { System.out.println("update"); } public void select() { System.out.println("select"); } }
-
现在制作一个动态代理的横切关注点,需要加在原有的业务前,原有业务执行前,执行这个切片
-
-
制作切片
-
public class Log implements MethodBeforeAdvice { ///** // * @param method:要执行目标对象的方法 // * @param args:参数 // * @param target:目标对象 // * @throws Throwable // */ public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行"); } }
-
before中是切片执行的方法,通知方式是before,前置通知
-
-
把这个横切关注点加入beans,和
-
<bean id="log" class="com.haoyun.log.Log"/> <bean id="UserServiceImpl" class="com.haoyun.service.UserServiceImpl"/>
-
-
applicationContext.xml配置AOP切入点,切片环绕
-
<aop:config> <!--切入点:expression:表达式(要执行的位置,UserServiceImpl.要切入的方法)--> <aop:pointcut id="pointcut" expression="execution(* com.haoyun.service.UserServiceImpl.*(..))"/> <!--执行环绕增加--> <!--把log切片,切入到pointcut切入点上--> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> </aop:config>
-
-
测试
-
@Test public void ProxyTest() { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); /*代理的是一个接口*/ UserService userserviceImpl = (UserService) context.getBean("UserServiceImpl",UserService.class); userserviceImpl.add(); }
-
执行add前会先执行log切面
-
使用自定义类
-
public class aspectDiy { public void beforeDiy(){ System.out.println("beforeDiy"); } public void afterDiy(){ System.out.println("afterDiy"); } }
-
<aop:config> <aop:aspect ref="aspectDip"> <!--切入点--> <aop:pointcut id="pointcut" expression="execution(* com.haoyun.service.UserServiceImpl.*(..))"/> <!--通知,切入到哪个点上--> <aop:before method="beforeDiy" pointcut-ref="pointcut"/> <aop:after method="afterDiy" pointcut-ref="pointcut"/> </aop:aspect> </aop:config>
-
选择对应的方法切入就行
-
beforeDiy add afterDiy
使用注解实现
-
先开启注解支持
-
<aop:aspectj-autoproxy/> <context:component-scan base-package="com.haoyun.pointCut"/>
-
@Aspect @Component public class AnnotationPointCut { @Before("execution(* com.haoyun.service.UserServiceImpl.*(..))") public void before(){ System.out.println(AnnotationPointCut.class.getName()+" before"); } @After("execution(* com.haoyun.service.UserServiceImpl.*(..))") public void after(){ System.out.println(AnnotationPointCut.class.getName()+" after"); } }
-
和之前一样测试就行
规范点的化使用第一种方法吧,切面小的话使用第二种方法,第三种方法也不是很简便,要设置切入点还挺麻烦,第一和第二种方法的切入点都可以复用,第三种方法切入点不好复用,差点意思