MENU

SpringAOP笔记

什么是AOP

Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码。

AOP相关术语

AOP相关术语

Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。

Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。

Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知

通知分为前置通知,后置通知,异常通知,最终通知,环绕通知(切面要完成的功能)

Introduction(引介):引介是一种特殊的通知在不修改类代码的前提下,

Introduction可以在运行期为类动态地添加一些方法或Field.

Target(目标对象):代理的目标对象

Weaving(织入):是指把增强应用到目标对象来创建新的代理对象的过程。

spring采用动态代理织入,而AspectJ采用编译期织入和类装在期织入

Proxy(代理):一个类被AOP织入增强后,就产生一个结果代理类

Aspect(切面):是切入点和通知(引介)的结合

  • Spring在运行期,生成动态代理对象,不需要特殊的编译器
  • Spring AOP的底层就是通过JDK动态代理或CGLib动态代理技术为目标Bean执行横向织入
  1. 若目标对象实现了若干接口,spring使用JDK的java.lang.reflect.Proxy类代理。
  2. 若目标对象没有实现任何接口,spring使用CGLIB库生成目标对象的子类。
  • 代理知识总结程序中应优先对接口创建代理,便于程序解耦维护
  • 标记为final的方法,不能被代理,因为无法进行覆盖

    • JDK动态代理,是针对接口生成子类,接口中方法不能使用final修饰
    • CGLib 是针对目标类生产子类,因此类或方法不能使final的
  • Spring只支持方法连接点,不提供属性连接
    [/tip]

Spring AOP增强类型

  • AOP联盟为通知Advice定义了org.aopalliance.aop.Interface.Advice
  • Spring按照通知Advice在目标类方法的连接点位置,可以分为5类

    • 前置通知 org.springframework.aop.MethodBeforeAdvice

      • 在目标方法执行前实施增强
    • 后置通知 org.springframework.aop.AfterReturningAdvice

      • 在目标方法执行后实施增强
  • 环绕通知 org.aopalliance.intercept.MethodInterceptor

    • 在目标方法执行前后实施增强
  • 异常抛出通知 org.springframework.aop.ThrowsAdvice

    • 在方法抛出异常后实施增强
  • 引介通知 org.springframework.aop.IntroductionInterceptor

    • 在目标类中添加一些新的方法和属性 (暂时不了解)

基于AspectJ的AOP开发(重点)

传统Spring AOP切面类型

  • Advisor:代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截
  • PointcutAdvisor:代表具有切点的切面,可以指定拦截目标类哪些方法
  • IntroductionAdvisor:代表引介切面,针对引介通知而使用切面(不要求掌握)

传统Advisor切面案例

  • ProxyFactoryBean常用可配置属性-target:代理的目标对象
  • proxyInterfaces:代理要实现的接口
  • 如果多个接口可以使用以下格式赋值
  <list>
      <value></value>
      ...
  </list>
  • 案例:
   <?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
          xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
          xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
   
   <!--    配置目标类-->
       <bean id="studentDao" class="com.xn2001.dao.StudentDaoImpl"/>
   <!--    前置通知类型-->
       <bean id="myBeforeAdvice" class="com.xn2001.MyBeforeAdvice"/>
   <!--    Spring的AOP 产生代理对象-->
       <bean id="studentDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
   <!--        配置目标类-->
           <property name="target" ref="studentDao"/>
   <!--        实现的接口-->
           <property name="proxyInterfaces" value="com.xn2001.dao.StudentDao"/>
   <!--        采用拦截的名称-->
           <property name="interceptorNames" value="myBeforeAdvice"/>
       </bean>
   </beans>
 //StudentDaoImpl
public class StudentDaoImpl implements StudentDao {
    public void find() {
        System.out.println("学生查询");
 }

    public void save() {
        System.out.println("学生保存");
 }

    public void update() {
        System.out.println("学生修改");
 }

    public void delete() {
        System.out.println("学生删除");
 }
}

//MyBeforeAdvice
public class MyBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("这是前置增强");
    }
}

//Demo
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo {
    @Resource(name = "studentDaoProxy")
    private StudentDao studentDao;

    @Test
    public void demo1(){
        studentDao.find();
        studentDao.delete();
        studentDao.save();
        studentDao.update();
    }
}

传统PointcutAdvisor 切点切面

  • 使用普通Advice作为切面,将对目标类所有方法进行拦截,不够灵活,在实际开发中常采用带有切点的切面
  • 常用PointcutAdvisor 实现类

    • Jdk RegexpMethodPointcut 构造正则表达式切点
    • DefaultPointcutAdvisor 它可以通过任意Pointcut和Advice 组合定义切面
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--目标类-->
    <bean id="studentDao" class="com.xn2001.dao.StudentDao"/>
    <!--配置通知类-->
    <bean id="myAroundAdvice" class="MyAroundAdvice"/>

    <!--一般的切面是使用通知作为切面,因为要对目标类的某个方法进行增强就需要配置一个带有切入点的切面-->
    <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <!--pattern配置正则表达式: .任意字符  *任意次数-->
        <property name="pattern" value=".*save.*"/>
        <property name="advice" ref="myAroundAdvice"/>
    </bean>
    <!--配置产生代理-->
    <bean id="studentDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="studentDao"/>
        <property name="proxyTargetClass" value="true"/>
        <property name="interceptorNames" value="myAdvisor"/>
    </bean>
</beans>
public class StudentDao{
       public void find() {
           System.out.println("学生查询");
       }

       public void save() {
           System.out.println("学生保存");
       }

       public void update() {
           System.out.println("学生修改");
       }

       public void delete() {
           System.out.println("学生删除");
       }
}
   
   public class MyAroundAdvice implements MethodInterceptor {
       public Object invoke(MethodInvocation methodInvocation) throws Throwable {
           System.out.println("这是环绕前增强-------------");
           Object obj = methodInvocation.proceed();
           System.out.println("这是环绕后增强-------------");
           return obj;
       }
   }
   
   @RunWith(SpringJUnit4ClassRunner.class)
   @ContextConfiguration("classpath:applicationContext.xml")
   public class Demo {
       @Resource(name="studentDaoProxy")
       private StudentDao studentDao;
       @Test
       public void demo(){
           studentDao.update();
           studentDao.save();
           studentDao.delete();
           studentDao.find();
       }
   }

传统自动创建代理

  • 前面的案例中,每个代理都是通过ProxyFactoryBean织入切面代理,在实际开发中,非常多的Bean每个都配置ProxyFactoryBean开发维护量巨大
  • 解决方案:自动创建代理
  • BeanNameAutoProxyCreator 根据Bean名称创建代理
  • DefaultAdvisorAutoProxyCreator 根据Advisor本身包含信息创建代理
  • AnnotationAwareAspectJAutoProxyCreator 基于Bean中的AspectJ注解进行自动代理
本站所有未注明转载的文章均为原创,并采用CC BY-NV-SA 4.0 授权协议,转载请注明来源。

Last Modified: March 24, 2020
Archives QR Code
QR Code for this page
Tipping QR Code
Leave a Comment

已有 1 条评论
  1. 看到就头大,自学一个月放弃了