Spring详解AOP

一、什么是代理模式?

代理模式就是给某个对象提供一个代理对象,由代理对象控制对原对象的控制,访问原对象的方法。

二、Spring AOP的理解

AOP:Aspect Oriented Programing,面向切面编程,是Spring的两大核心思想之一,是一种编程的思想,也是对面向对象思想不足的补充和扩展,因为万物皆对象的这种思想,将现实世界所有的事物映射为Java世界中的一个个对象,可以看作是纵向在设计一个个类,而当这些类都需要一些公共的实现代码时,比如说日志、权限,抽象类或接口的设计已经不太能满足这个需求了,因为Java是单继承,而且使用抽象类或接口会使整个结构变得更复杂,所以出现了AOP,面向切面编程,横向去将这些类的公共代码(系统代码)提炼出来,使用代理和反射的机制交由代理对象去实现,保证了原业务代码的纯粹性,也提高了系统的可维护性、可扩展性。

三、Spring AOP中常见通知的类型

  • Before:前置通知
  • After:后置通知
  • AfterReturning:有返回值的后置通知,当方法正常执行后,执行该通知;如果方法执行时出现异常,则不执行该通知
  • AfterThrowing:异常通知,方法出现异常时,执行该通知
  • Around:环绕通知

四、Spring AOP的实现

  • 使用Spring AOP

    📗 第一步,定义通知类,继承相关接口,例如:MethodBeforeAdvice,AfterAdvice,AfterReturningAdvice,ThrowsAdvice,MethodInterceptor,重写或自定义相关方法。

    📘 第二步:配置XML:

    <!-- 大前提 -->
    <!-- 通知类 -->
    <bean id="logAdviceBean" class="com.apesource.advice.LogAdvice"/>
    
    <!-- 目标类 -->
    <bean id="homeControllerBean" class="com.apesource.web.controller.HomeController"/>
    

    形式1:手动代理:使用ProxyFactoryBean手动为目标类创建代理类。

    缺点:每个目标类都要写一个Bean,很繁琐,在获取Bean的时候需要获取代理类Bean。

    <!-- 手动代理 -->
    <bean id="homeControllerProxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
        <!-- 注入目标类 -->
        <property name="target" ref="homeControllerBean"/>
        
      <!-- 注入通知类 -->
        <property name="interceptorNames" value="logAdviceBean"/>
    </bean>
    

    形式2:自动代理:使用BeanNameAutoProxyCreator自动为所匹配的Bean创建代理类。

    优点:简洁,在获取Bean的时候直接获取目标类的Bean,Spring会自动地创建代理类对象并返回。

    <!-- 自动代理(匿名Bean) -->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <!-- 注入符合表达式的目标类 -->
        <property name="beanNames" value="*ControllerBean"/>
        
        <!-- 注入通知类 -->
        <property name="interceptorNames" value="logAdviceBean"/>
    </bean>
    

    📙 注入的通知类类型:

    1. 普通的通知类:类级别的通知,会使注入该通知的类的所有方法都执行该通知,颗粒度太大。

      <bean id="logAdviceBean" class="com.apesource.advice.LogAdvice"/>
      
    2. 高级的通知类:Advisor切面,方法级别的通知,可以具体到某一个符合规则的方法,颗粒度小。

      实现方式1:

      <!-- 实现方式1 -->
      <!-- 1.1切入点(Pointcut):通过正则表达式描述指定切入点 -->
      <bean id="createMethodPointcutBean" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
          <!-- 描述符合表达式的方法 -->
          <property name="pattern" value=".*create.*"/>
      </bean>
      
      <!-- 和1.1类似的实现 -->
      <!-- <bean id="controllerLogMethodPointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">-->
          <!-- 描述符合表达式的方法 -->
      <!--<property name="mappedName" value="*create*"/>-->
      <!--</bean>-->
      
      <!-- 1.2 -->
      <!-- Advisor = Advice(通知) + Pointcut(切入点) -->
      <bean id="performanceAdvisorBean" class="org.springframework.aop.support.DefaultPointcutAdvisor">
          <!--注入切入点-->
          <property name="pointcut" ref="createMethodPointcutBean"/>
      
          <!--注入通知-->
          <property name="advice" ref="performanceBean"/>
      </bean>
      

      实现方式2:一步到位

      <!-- 实现方式2 -->
      <bean class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
          <!-- 通过正则表达式描述切入点,并注入 -->
          <property name="mappedName" value="*create*"/>
          
          <!--注入通知-->
          <property name="advice" ref="logAdviceBean"/>
      </bean>
      
  • 使用AspectJ框架:

    方式1:使用POJO+XML的形式

    📗 第一步,自定义通知类,自定义通知方法。

    public class LogAdvice{
        private Logger logger = Logger.getLogger(LogAdvice.class.getName());
    
        public void beginLogging(JoinPoint jp){
            logger.info("日志开始");
        }
    
        public void endLogging(JoinPoint jp){
            logger.info("日志结束");
        }
    }
    

    📘 第二步,进行XML配置

    1.1 首先加入aop的命名空间配置

    <beans xmlns:aop="http://www.springframework.org/schema/aop"
    xsi:schemaLocation="http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    

    1.2 定义通知类

    <bean id="logAdvice" class="com.apesource.advice.LogAdvice"/>
    

    1.3 进行aop配置

    <!-- 顶层aop配置 -->
    <aop:config>
        <!-- 定义切面,注入通知类 -->
        <aop:aspect ref="logAdvice">
            <!--定义切点-->
            <aop:pointcut id="adminControllerPointcut" expression="execution(* com.apesource.web.controller.*.handler*(..))"/>
    
            <!-- 配置前置同通知 -->
            <aop:before method="beginLogging" pointcut-ref="adminControllerPointcut"/>
    
            <!-- 配置后置通知 -->
            <aop:after method="endLogging" pointcut-ref="adminControllerPointcut"/>
        </aop:aspect>
    </aop:config>
    

    方式2:使用纯注解

    📗 第一步,自定义通知类,使用相关注解,并将通知类交给容器管理

    @Aspect // 声明为一个切面类
    @Component
    public class LogAdvice2 {
        private Logger logger = Logger.getLogger(LogAdvice.class.getName());
    
        @Before("execution(* com.apesource.web.controller.*.handler*(..))")
        public void beginLogging(JoinPoint jp){
            logger.info("日志开始");
    
        }
    
        @After("execution(* com.apesource.web.controller.*.handler*(..))")
        public void endLogging(JoinPoint jp){
            logger.info("日志结束");
        }
    }
    

    📘 第二步,开启AspectJ自动代理

    @ComponentScan // 默认扫描同包之下
    @EnableAspectJAutoProxy
    public class SystemConfig {
    
    }
    

相关注解:

@Aspect

@EnableAspectJAutoProxy

@Pointcut

@Before

@After

@AfterReturning

@AfterThrowing

@Around

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 200,612评论 5 471
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,345评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 147,625评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,022评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,974评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,227评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,688评论 3 392
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,358评论 0 255
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,490评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,402评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,446评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,126评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,721评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,802评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,013评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,504评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,080评论 2 341