• AOP


    什么是AOP

    • AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。
    • AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。
    • 利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

    AOP在Spring中的作用

            提供声明式事务,允许用户自定义切面

    • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点,如:日志、安全、缓存、事务等
    • 切面(Aspect):横切关注点,被模块化的特殊对象。即,它是一个类
    • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法
    • 目标(Target):被通知对象
    • 代理(Proxy):向目标对象应用通知之后创建的对象
    • 切入点(PointCut):切面通知执行的“地点”的定义
    • 连接点(JoinPoint):与切入点匹配的执行点

            SpringAOP中,通过Advice定义横切逻辑,Spring中支持5中类型的Advice

            即AOP在不改变原有代码的情况下,去增加新的功能

             即AOP在不改变原有代码的情况下,去增加新的功能

    使用Spring实现AOP

    【重点】使用AOP织入,需要在pom.xml导入一个依赖包

    1. <dependencies>
    2. <dependency>
    3. <groupId>org.aspectjgroupId>
    4. <artifactId>aspectjweaverartifactId>
    5. <version>1.9.9version>
    6. dependency>
    7. dependencies>

    环境搭建

            1.接口

    1. public interface UserService {
    2. public void insert();
    3. public void delete();
    4. public void update();
    5. public void select();
    6. }

            2.接口实现

    1. public class UserServiceImpl implements UserService{
    2. @Override
    3. public void insert() {
    4. System.out.println("增加了一个用户");
    5. }
    6. @Override
    7. public void delete() {
    8. System.out.println("删除了一个用户");
    9. }
    10. @Override
    11. public void update() {
    12. System.out.println("修改了一个用户");
    13. }
    14. @Override
    15. public void select() {
    16. System.out.println("查看了一个用户");
    17. }
    18. }

    方式一:使用Spring的API接口(主要Spring API接口实现)

    前置通知:

    1. import org.springframework.aop.AfterReturningAdvice;
    2. import java.lang.reflect.Method;
    3. public class AfterLog implements AfterReturningAdvice {
    4. //returnValue(o):返回值
    5. //
    6. @Override
    7. public void afterReturning(Object returnValue, Method method, Object[] objects, Object o1) throws Throwable {
    8. System.out.println("执行了" + method.getName() + "方法,返回结果为" + returnValue);
    9. }
    10. }

    小结:

    • returnValue(o):返回值

    后置通知:

    1. import org.springframework.aop.MethodBeforeAdvice;
    2. import java.lang.reflect.Method;
    3. public class BeforeLog implements MethodBeforeAdvice {
    4. //method:要执行的参数目标对象的方法
    5. //objects(ars):参数
    6. //target(o):目标对象
    7. @Override
    8. public void before(Method method, Object[] args, Object target) throws Throwable {
    9. System.out.println(target.getClass().getName() +"的"+method.getName()+"被执行了");
    10. }
    11. }

    小结:

    • method:要执行的参数目标对象的方法
    • objects(ars):参数
    • target(o):目标对象

    applicationContext.xml

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:aop="http://www.springframework.org/schema/aop"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. https://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/aop
    8. https://www.springframework.org/schema/aop/spring-aop.xsd">
    9. <bean id="userService" class="com.yuan.service.UserServiceImpl"/>
    10. <bean id="afterLog" class="com.yuan.log.AfterLog"/>
    11. <bean id="beforeLog" class="com.yuan.log.BeforeLog"/>
    12. <aop:config>
    13. <aop:pointcut id="pointcut" expression="execution(* com.yuan.service.UserServiceImpl.*(..))"/>
    14. <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
    15. <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
    16. aop:config>
    17. beans>

    测试

    1. import com.yuan.service.UserService;
    2. import org.springframework.context.ApplicationContext;
    3. import org.springframework.context.support.ClassPathXmlApplicationContext;
    4. public class MyTest {
    5. public static void main(String[] args) {
    6. ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    7. //动态代理 代理的是接口
    8. UserService userService = (UserService) context.getBean("userService");
    9. userService.insert();
    10. userService.select();
    11. }
    12. }

    结果


    方式二:自定义来实现AOP(主要是切面定义)

    自定义类

    1. public class DiyPointCut {
    2. public void before(){
    3. System.out.println("======方法执行前======");
    4. }
    5. public void after(){
    6. System.out.println("======方法执行后======");
    7. }
    8. }

    applicationContext.xml

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:aop="http://www.springframework.org/schema/aop"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. https://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/aop
    8. https://www.springframework.org/schema/aop/spring-aop.xsd">
    9. <bean id="userService" class="com.yuan.service.UserServiceImpl"/>
    10. <bean id="afterLog" class="com.yuan.log.AfterLog"/>
    11. <bean id="beforeLog" class="com.yuan.log.BeforeLog"/>
    12. <bean id="diy" class="com.yuan.diy.DiyPointCut"/>
    13. <aop:config>
    14. <aop:aspect ref="diy">
    15. <aop:pointcut id="point" expression="execution(* com.yuan.service.UserServiceImpl.*(..))"/>
    16. <aop:before method="before" pointcut-ref="point"/>
    17. <aop:after method="after" pointcut-ref="point"/>
    18. <aop:around method="around" pointcut-ref="point"/>
    19. aop:aspect>
    20. aop:config>
    21. beans>

    测试类与方式一相同,结果如下


    方式三:使用注解实现

    注解类

    1. import org.aspectj.lang.ProceedingJoinPoint;
    2. import org.aspectj.lang.annotation.After;
    3. import org.aspectj.lang.annotation.Around;
    4. import org.aspectj.lang.annotation.Aspect;
    5. import org.aspectj.lang.annotation.Before;
    6. //方式三:使用注解方式实现AOP
    7. @Aspect //标注这个类是一个切面
    8. public class AnnotationPointCut {
    9. @Before("execution(* com.yuan.service.UserServiceImpl.*(..))")
    10. public void before(){
    11. System.out.println("======方法执行前======");
    12. }
    13. @After("execution(* com.yuan.service.UserServiceImpl.*(..))")
    14. public void after(){
    15. System.out.println("======方法执行后======");
    16. }
    17. //在环绕增强中,我们给定一个参数,代表我们要获取处理切入的点
    18. @Around("execution(* com.yuan.service.UserServiceImpl.*(..))")
    19. public void around(ProceedingJoinPoint jp) throws Throwable {
    20. System.out.println("环绕前");
    21. Object proceed = jp.proceed();
    22. System.out.println("环绕后");
    23. }
    24. }

    applicationContext.xml

    1. "1.0" encoding="UTF-8"?>
    2. <beans xmlns="http://www.springframework.org/schema/beans"
    3. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    4. xmlns:aop="http://www.springframework.org/schema/aop"
    5. xsi:schemaLocation="http://www.springframework.org/schema/beans
    6. https://www.springframework.org/schema/beans/spring-beans.xsd
    7. http://www.springframework.org/schema/aop
    8. https://www.springframework.org/schema/aop/spring-aop.xsd">
    9. <bean id="userService" class="com.yuan.service.UserServiceImpl"/>
    10. <bean id="afterLog" class="com.yuan.log.AfterLog"/>
    11. <bean id="beforeLog" class="com.yuan.log.BeforeLog"/>
    12. <bean id="annotationPointCut" class="com.yuan.diy.AnnotationPointCut"/>
    13. <aop:aspectj-autoproxy proxy-target-class="false"/>
    14. beans>

    测试类与方式一相同,结果如下

    小结:

    • 中JDK(默认proxy-target-class="false")   cglib(proxy-target-class="true") 
    • 在注解类中要先写了方法才能使用注解

    扩展:

    小结

    Aspectj切入点语法定义 

    expression="execution(* com.yuan.service.ServiceImpl..*.*(..))

    • execution()是最常用的切入点函数
    • execution();表达式主体
    • 如果把UserServiceImpl改成* 就表示所有类的所有方法
    • 第一个*号:表示返回类型,*号表示所有的类型
    • com.yuan.service.ServiceImpl包,AOP所切的服务的包名,即,我们的业务部分
    • 包后面的..表示当前包及子包
    • 第二个*号:表示类名,*号表示所有的类
    • .*(..);最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个点表示任意参数
       

  • 相关阅读:
    网络安全专业学习路线
    思维模型 飞轮效应
    关于Springboot的@Profile的写法以及多个profile的写法排坑(“!profile1 && !profile2“ 的写法)
    Visual Studio运用Entity Framework连接数据库
    《向量数据库指南》——向量数据库Milvus Cloud快速打造知识库 AI 应用
    Springboot求职招聘系统毕业设计源码250911
    Ubuntu 的护眼软件 :RedShift
    Yunfly 一款高效、性能优异的 node.js web 框架
    golang读取yaml文件
    基础组件-流量回放平台设计
  • 原文地址:https://blog.csdn.net/weixin_48426115/article/details/126856514