zoukankan      html  css  js  c++  java
  • Spring AOP学习笔记


    Spring AOP

    Spring 中 AOP 代理由 Spring 的 IoC 容器负责生成、管理,其依赖关系也由 IoC 容器负责管理。一些AOP的概念:

    • 切面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。
    • 连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
    • 通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。
    • 切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。
    • 引入(Introduction):添加方法或字段到被通知的类。Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现IsModified接口,来简化缓存。
    • 目标对象(Target Object):包含连接点的对象,也被称作被通知或被代理对象。
    • AOP代理(AOP Proxy):AOP框架创建的对象,包含通知。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。
    • 编织(Weaving):组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。

    一、基于代理的AOP实现

    1. 代理类

    public class ServiceHelper implements MethodBeforeAdvice, AfterReturningAdvice {
    	public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
    		System.out.println("方法执行开始!");
    	}
    	public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
    		System.out.println("方法执行结束!");
    	}
    }
    

    2. XML配置

    <!-- 定义被代理者 -->
    <bean id="user" class="com.aop.service.UserServiceImpl"></bean>
    
    <!-- 定义通知内容,也就是切入点执行前后需要做的事情 -->
    <bean id="serviceHelper" class="com.aop.helper.ServiceHelper"></bean>
    
    <!-- 定义切入点位置 -->
    <bean id="servicePointcut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
    <property name="pattern" value=".*"></property>
    </bean>
    
    <!-- 使切入点与通知相关联,完成切面配置 -->
    <bean id="serviceHelperAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
    <property name="advice" ref="serviceHelper"></property>   	
       <property name="pointcut" ref="servicePointcut"></property>
    </bean>
    
    <!-- 设置代理 -->
    <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 代理的对象,有记录方法开始结束能力 -->
    <property name="target" ref="user"></property>
    <!-- 使用切面 -->
    <property name="interceptorNames" value="serviceHelperAdvisor"></property>
    <!-- 代理接口,service接口 -->
    <property name="proxyInterfaces" value="com.aop.service.IUserService"></property> 
    </bean>
    

    二、通过AspectJ提供的注解实现AOP

    1. 切面代码

    @Aspect
    public class ServiceHelper{
        @Pointcut("execution(* *.*())")
        public void userPointcut(){}
        
        @Before("userPointcut()")
        public void before(){
            System.out.println("方法执行开始!");
        }
        
        @AfterReturning("userPointcut()")
        public void after(){
            System.out.println("方法执行结束!");
        }
    }
    

    2. XML配置

    <aop:aspectj-autoproxy />
    <!-- 定义通知内容,也就是切入点执行前后需要做的事情 -->
    <bean id="serviceHelper" class="com.aop.helper.ServiceHelper"></bean>
    <!-- 定义被代理者 -->
    <bean id="user" class="com.aop.service.UserServiceImpl"></bean>
    

    三、使用Spring来定义纯粹的POJO切面

    1.

    public class ServiceHelper{
        public void before(){
            System.out.println("方法执行开始!");
        }
        
        public void after(){
            System.out.println("方法执行结束!");
        }
    }
    

    2. XML配置

    2.1 写法一
    <aop:config>
    	<aop:aspect ref="serviceHelper">
    		<aop:before method="before" pointcut="execution(* *.*(..))" />
    		<aop:after method="after" pointcut="execution(* *.*(..))" />
    	</aop:aspect>
    </aop:config>
    
    2.2. 写法二
    <aop:config>
    	<aop:aspect ref="serviceHelper">
            <aop:pointcut id="serviceHelpers" expression="execution(* *.*(..))" />
            <aop:before pointcut-ref="serviceHelper" method="before" />
            <aop:after pointcut-ref="serviceHelper" method="after" />       	
        </aop:aspect>
    </aop:config>
    

    Springboot 实现AOP

    其实搞明白AOP是什么之后(基于动态代理实现面向切面编程的一种思想),无论在哪里使用都很简单,但是由于最近做的好多项目都使用springboot,所以就在补充一下,超级无敌简单

    依赖的包,pom中引入即可

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>
    

    springboot实现AOP有两种方式:一是申明的方式(基于XML),二是注解的方式(基于AspectJ),由于个人喜好只说说注解的方式实现AOP,

    一、实现方式一(编写切入点表达式)

    @Service
    public class LogService {
        private final Logger logger = LoggerFactory.getLogger(LogService.class);
    
        public void search(){
            logger.info("查询方法被执行");
        }
    }
    
    @Aspect
    @Component
    public class LogAspect {
        private final Logger logger = LoggerFactory.getLogger(LogAspect.class);
        
        @Pointcut("execution(public * com.dafeng.service.LogService.*(..))")//切入点描述 这个是切入点
        public void logPointcut(){}//签名,可以理解成这个切入点的一个名称
    
        @Before("logPointcut()") //在切入点的方法执行之前
        public void before(JoinPoint joinPoint) {
            logger.info("方法执行前。。。");
        }
    
        @After("logPointcut()") //在切入点的方法执行之后
        public void after(JoinPoint joinPoint) {
            logger.info("方法执行后。。。");
        }
    }
    

    执行结果:

    2020-03-01 13:40:38.894  INFO 35973 --- [nio-8080-exec-1] com.dafeng.service.LogAspect             : 方法执行前。。。
    2020-03-01 13:40:38.903  INFO 35973 --- [nio-8080-exec-1] com.dafeng.service.LogService            : 查询方法被执行
    2020-03-01 13:40:38.903  INFO 35973 --- [nio-8080-exec-1] com.dafeng.service.LogAspect             : 方法执行后。。。
    

    二、 实现方式二(自定义注解)

    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Log {
        String value() default "";
    }
    
    @Service
    public class LogService {
        private final Logger logger = LoggerFactory.getLogger(LogService.class);
    
        @Log // 此处添加自定义注解
        public void search(){
            logger.info("查询方法被执行");
        }
    }
    
    @Aspect
    @Component
    public class LogAspect {
        private final Logger logger = LoggerFactory.getLogger(LogAspect.class);
        
        @Pointcut("@annotation(com.dafeng.annotation.Log)")//切入点描述使用自定义注解 这个是切入点
        public void logPointcut(){}//签名,可以理解成这个切入点的一个名称
    
        
        @Before("logPointcut()") //在切入点的方法执行之前要干的
        public void before(JoinPoint joinPoint) {
            logger.info("方法执行前。。。");
        }
    
        @After("logPointcut()") //在切入点的方法执行之后要干的
        public void after(JoinPoint joinPoint) {
            logger.info("方法执行后。。。");
        }
    }
    

    执行结果:

    2020-03-01 14:12:35.434  INFO 40304 --- [nio-8080-exec-1] com.dafeng.service.LogAspect             : 方法执行前。。。
    2020-03-01 14:12:35.441  INFO 40304 --- [nio-8080-exec-1] com.dafeng.service.LogService            : 查询方法被执行
    2020-03-01 14:12:35.442  INFO 40304 --- [nio-8080-exec-1] com.dafeng.service.LogAspect             : 方法执行后。。。
  • 相关阅读:
    css 盒模型
    Dom事件类-文档对象模型
    BFC-边距重叠解决方案
    三栏布局的五种方式--左右固定,中间自适应
    为什么必须先写组件再写vue的实例
    H5跳小程序安卓机出现白屏的问题
    关于iframe标签的src属性
    子组件让父组件进行刷新vuex
    html 插件
    git 其他merge
  • 原文地址:https://www.cnblogs.com/dafengdeai/p/12389730.html
Copyright © 2011-2022 走看看