zoukankan      html  css  js  c++  java
  • Spring中AOP的实现

    Spring中整合了AOP的功能,虽然有不足,没有专门做AOP框架的那么完美,但是用一用感觉还是不错的

    一些概念:

    AOP 面向切面编程

    aspect 切面/切面类(我个人认为一个真正被解耦的程序,切面类中的功能可以切入到 任何一个目标类中 无所谓是service层或者说是dao层中的类)

    joinPoint 连接点

    在spring的aop中只有 类中的方法 可以做连接点,每一个方法都可以是一个连接点.

    pointCut 切入点 

    一组连接点的集合

    advice 通知/拦截器

    用来控制切面类将来到底是织入到切入点的前面、后面或者是抛异常的时候。

    adivsor 增强器
    用来筛选类中的哪些方法是我们的连接点(哪些方法需要被拦截).

    target 目标对象

    proxy 代理对象

    wave 织入

    -----------------------

    advice(通知)的类型:

    前置通知(Before advice):
    在某些连接点(join point)之前执行的通知

    返回后通知(After returning advice):
    在某些连接点(join point)正常完成后执行的通知(方法正常结束,没有异常)

    抛出异常后通知(After throwing advice):
    在某些连接点(join point)抛出异常退出时执行的通知

    后通知(After (finally) advice):
    当某些连接点(join point)退出的时候执行的通知

    环绕通知(Around Advice):
    包围一个连接点(join point)的通知,例如事务的处理,就需要这样的通知,因为事务需要在方法前开启,在方法后提交,以及方法抛出异常时候回滚

    注:在spring中,连接点(join point)指的就是方法

    Spring中提供了AOP的实现方式 在XMl中配置只需要三步就可以实现

    1.配置目标类
    2.配置拦截器(配置切面类【可选】)
    3.配置代理对象

    配置xml文件:

    1.首先是配置目标类

    <!-- 配置dao层对象 -->
    <bean id="dao" class="com.briup.aop.dao.AccountDaoImpl"/>
    
    <!-- 配置一个测试账户 -->
    <bean name="account" class="com.briup.aop.pojo.Account">
    <property name="id" value="1"></property>    
    <property name="name" value="tom"></property>    
    <property name="balance" value="1000"></property>    
    </bean>
    
    <!-- 配置目标对象 -->
    <bean name="target" 
    class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
    <property name="account" ref="account"></property>
    </bean>

    2.配置拦截器

    <!-- 配置切面类 -->
    <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>
        
    <!-- 配置advice -->
    <bean name="beforeAdvice" class="com.briup.aop.before.BeforeAdvice">
    <!-- 注入切面类对象 -->
    <property name="logger" ref="logger"></property>
    </bean>

    3.配置代理对象

    <!-- 这里使用的是spring的一个代理对象工厂类产生的 -->
    <bean name="proxy" 
    class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 注入目标对象 -->
    <property name="target" ref="target"></property>
    
    <!-- 注入目标对象所实现的接口 可以有多个接口 -->
    <!-- 注入代理类需要实现的接口 代理类实现接口与目标类实现接口相同 -->
    <property name="proxyInterfaces">
    <list>
    <value>com.briup.aop.service.IAccountService</value>
    </list>
    </property>
    
    <!-- 注入advice 可以有多个 -->
    <property name="interceptorNames">
    <list>
    <value>beforeAdvice</value>
    </list>
    </property>
    
    </bean>

    这样配置有三个问题:
    1.这个目标类对应接口下的方法都被加入了功能
    2.需要为每一个目标类进行配置
    3.目标类必须实现接口

    首先我们解决第一个问题
    我们的Spring中提供了advisor(增强器),增强器包装了一下advice(拦截器),可以筛选向接口中的那个方法添加功能

    1.首先是配置目标类

    <!-- 配置dao层对象 -->
    <bean id="dao" class="com.briup.aop.dao.AccountDaoImpl"/>
    
    <!-- 配置一个测试账户 -->
    <bean name="account" class="com.briup.aop.pojo.Account">
    <property name="id" value="1"></property>    
    <property name="name" value="tom"></property>    
    <property name="balance" value="1000"></property>    
    </bean>
    <!-- 配置目标对象 -->
    <bean name="target" 
    class="com.briup.aop.service.AccountServiceImpl">
    <property name="accountDao" ref="dao"></property>
    <property name="account" ref="account"></property>
    </bean>

    2.配置拦截器

    <!-- 配置切面类 -->
    <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>
    
    <!-- 配置advice -->
    <bean name="beforeAdvice" class="com.briup.aop.before.BeforeAdvice">
    <!-- 注入切面类对象 -->
    <property name="logger" ref="logger"></property>
    </bean>

    3.添加增强器

    <!-- 配置advisor 增强器-->
    <!-- 作用:筛选要拦截(要代理)的方法 -->
    <bean name="advisor" 
    class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <!-- 注入advice-->
    <property name="advice" ref="beforeAdvice"></property>
    <!-- 注入需要被拦截的目标对象中的方法(连接点) -->
    <property name="patterns">
    <list>
    <value>.*bankAction</value> <!--单个字符出现0到多次-->
    </list>
    </property>
    </bean>
    <!--RegexpMethodPointcutAdvisor默认的正则表达式选择方法-->
    <!--NameMatchMethodPointcutAdvisor按照方法名匹配-->

    4.配置代理对象

    <!-- 这里使用的是spring的一个代理对象工厂类产生的 -->
    <bean name="proxy" 
    class="org.springframework.aop.framework.ProxyFactoryBean">
    
    <!-- 注入目标对象 -->
    <property name="target" ref="target"></property>
    
    <!-- 注入目标对象所实现的接口 可以有多个接口 -->
    <!-- 注入代理类需要实现的接口 代理类实现接口与目标类实现接口相同 -->
    <property name="proxyInterfaces">
    <list>
    <value>com.briup.aop.service.IAccountService</value>
    </list>
    </property>
    
    <!-- 注入advice/advisor 可以有多个 -->
    <property name="interceptorNames">
    <list>
    <value>advisor</value>
    </list>
    </property>
    </bean>

    我们处理了第一个问题,被处理的方法可以指定

    我们开始解决第二个问题
    自动的进行配置:自动代理:DefaultAdvisorAutoProxyCreator类的使用

    xml配置文件:

    1.配置拦截器

    <!-- 配置切面类 -->
    <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>
    
    <!-- 配置advice -->
    <bean name="beforeAdvice" 
    class="com.briup.aop.before.BeforeAdvice">
    <!-- 注入切面类对象 -->
    <property name="logger" ref="logger"></property>
    </bean>

    2.添加增强器

    <!-- 配置advisor -->
    <!-- 作用:筛选要拦截的方法 -->
    <bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <!-- 注入advice -->
    <property name="advice" ref="beforeAdvice"></property>
    <!-- 注入需要被拦截的目标对象中的方法 -->
    <property name="patterns">
    <list>
    <value>.*bankAction</value>
    </list>
    </property>
    </bean>

    配置目标对象,这里的对象中只要有增强器中的方法,就可以当作代理对象,Cgilb代理默认的将含有增强器中的方法的
    所有对象都进行了处理,比如以下这个target对象,从容器中拿出后就是加入了功能的了,但是这些对象得要放在一个容器下面

    在Spring中最需要注意的就是对象在不在容器中,对象不在容器中就没办法受到Spring框架的控制了

    <bean name="target" 
    class="com.briup.aop.service.AccountServiceImpl">
    </bean>

    3.实现自动代理

    <!-- 配置代理对象 -->
    <!-- 这里使用自动代理的方式 autoproxy -->
    <!-- 注意:这不是一个工厂类,所以不能用过proxy来拿代理对象 -->
    <bean name="proxy" 
    class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
    </bean>

    这样做就可以自动的对需要功能的方法进行代理处理了,也不用实现接口了

    使用自动代理的时候需要注意的方面:
    1.当前的配置里面"一定要有"一个advisor的配置
    2.不需要向自动代理类中注入任何信息
    3.不管目标对象是否实现了一个或多接口,自动代理的方式都能够为它产生代理对象(CGLib的方式).
    4.从spring容器中拿代理对象的时候,需要通过目标对象的名字来拿。
    5.spring如何确定配置文件中哪个bean是作为目标对象:
    通过advisor中筛选的方法,如果这个bean中含有advisor中所配置的方法,则这个bean将来称为我们的目标对象进行代理

    但是又有问题来了:
    我们对所有含有同名方法的类对象进行了处理,如果想为指定类对象中的方法进行处理呢?

    Spring同样进行了处理:

    通过名字进行自动代理:BeanNameAutoProxyCreator类的使用

    xml配置文件:

    1.配置拦截器

    <!-- 配置切面类 -->
    <bean name="logger" class="com.briup.aop.aspect.MyLogger"></bean>
    <!-- 配置advice -->
    <bean name="beforeAdvice" 
    class="com.briup.aop.before.BeforeAdvice">
    <!-- 注入切面类对象 -->
    <property name="logger" ref="logger"></property>
    </bean>

    2.添加增强器

    <!-- 配置advisor -->
    <!-- 作用:筛选要拦截的方法 -->
    <bean name="advisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
    <!-- 注入advice -->
    <property name="advice" ref="beforeAdvice"></property>
    <!-- 注入需要被拦截的目标对象中的方法 -->
    <property name="patterns">
    <list>
    <value>.*bankAction</value>
    </list>
    </property>
    </bean>

    <!-- 配置目标对象 -->

    <bean name="target" class="com.briup.aop.service.AccountServiceImpl"> </bean>
    
    <bean name="target2" class="com.briup.aop.service.AccountServiceImpl"> </bean>
    
    <bean name="target3" class="com.briup.aop.service.AccountServiceImpl"></bean>

    3.实现自动代理

    <!-- 配置代理对象 -->
    <!-- 这里使用自动代理的方式 autoproxybyname -->
    <bean name="proxy" class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
    <!-- 注入需要被代理的对象名字 -->
    <property name="beanNames">
    <list>
    <value>target</value>
    <value>target2</value>
    <value>dao</value>
    <value>service*</value>
    </list>
    </property>
    
    <!-- 注入advice或者advisor -->
    <property name="interceptorNames">
    <list>
    <value>advisor</value>
    </list>
    </property>
    </bean>


    使用byName自动代理的时候需要注意的方面:
    1.当前的配置里面"有没有"advisor的配置"都没关系"
    有advisor可以精确选择加强功能的方法,没有就是类中的所有方法了

    2.需要向自动代理类中注入被代理目标对象的名字已经advice或者advisor
    就是说advisor中指定的方法在 被代理目标对象 中存在

    3.不管目标对象是否实现了一个或多接口,自动代理的方式都能够为它产生代理对象.

    4.从spring容器中拿代理对象的时候,需要通过目标对象的名字来拿。
    这一点在DefaultAdvisorAutoProxyCreator的使用中就说过了
    可以说 目标对象加入了功能,变成了代理对象

    Spring中封装了AspectJ
    所以我们也可以使用到这种框架的功能了,Spring中提供了aop:config标签,使用aop的专用标签来完成相关的配置.这个标签我也是正在研究,据说挺好用的☺。

  • 相关阅读:
    ASP.Net WebForm温故知新学习笔记:一、aspx与服务器控件探秘
    ASP.Net WebForm温故知新学习笔记:一、aspx与服务器控件探秘
    路由器原理(一)
    python人工智能——机器学习——机器学习基础
    python人工智能——机器学习——机器学习基础
    python人工智能——机器学习——数据的降维
    python人工智能——机器学习——数据的降维
    python人工智能——机器学习——数据的降维
    Common Subsequence
    Common Subsequence
  • 原文地址:https://www.cnblogs.com/Magic-Li/p/11755241.html
Copyright © 2011-2022 走看看