Spring理论知识学习笔记(七)

AOP

全程: Aspect Oriented Programming .意思为: 面向切面编程通过预编译方式运行期动态管理实现程序功能的统一维护的一种技术。

主要的功能是?

:日志记录性能统计安全控制事务处理异常处理等等

切面是和功能垂直的。如下图:
在这里插入图片描述

关注点是横向。

AOP实现方式?

  • 预编译

    ​ AsPectJ

  • 运行期动态代理(JDK动态代理,CGLib动态代理)

    ​ SpringAOP

    ​ JbossAOp

AOP的几个相关概念:

  1. 切面(Aspect)

    一个关注点的模块化,这个关注点可能会横切多个对象。

    比如上面的图所示,事务管理,横切了多个对象。将涉及管理多个对象。

  2. 连接点(Joinpoint)

    程序执行构成中的某个特定的点。比如 类的 某个方法。

  3. 通知(Advice)

    在切面的某个特定的连接点上执行的动作。下面是通知类型:

    名称说明
    前置通知在某个连接点(JoinPoint)之前执行的通知,但不能阻止连接
    点前的执行,(除非他抛出一个遗异常)
    返回后通知在某个连接点正常执行完成后的通知,
    抛出异常后通知抛出异常后,进行通知
    后通知不论是正常还是异常退出,都会在执行后通知。
    环绕通知环绕环绕,顾名思义,就是包围一个连接点的通知
  4. 切入点(Pointcut)

    匹配连接点的断言,在AOP中通知和一个切入点表达式关联

  5. 引入(Introduction)

    在不修改代码的前提下,为类添加新的方法和属性

  6. 目标对象

    被一个或者多个切面所通知的对象。

    比如 有个订单的service,和商品的service。切面通知 此两个对象。

  7. AOP代理(AOP Proxy)

    AOP框架创建的对象,用来实现切面契约

  8. 织入(Weaving)

    把切面和对象关联起来, 把切面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象

    分为:

    • ​ 编译时织入
    • ​ 类加载时织入
    • ​ 执行时织入
AOP用途:

​ 提供了企业服务,特别是EJB的替代服务的声明。允许用户定制自己的方面,已完成OOP和AOP的互补使用。

Spring的AOP的实现

​ 纯java实现,无需特殊的编译过程,不需要控制类加载器层次

​ 目前呢,支持持方法执行连接点,即通知SpringBean的方法来执行

​ 不是为了提供最完整的AOP实现,虽然尽管他非常强大。。而是侧重于提供一种AOP实现和SpiringIoc容器之 间的整合。用于帮助解决企业应用中的常见问题。

有接口和没接口的SPringAOP实现区别
  • 对于有接口的AOP实现:

    Spring AOp默认使用标准的JavaSe动态代理作为AOP代理,这使得任何接口都可以被代理。。

  • 对于没有接口的AOP实现:

    如果一个业务对象并没有实现对象,AOP也可以使用CGLIB来进行代理。

​ AOP配置切面aspect

​ 在Spring-config.xml中声明aop:config和aop:aspect标签并使用它:

  1. 首先,先在test包下创建aoppractice文件夹

  2. 然后再该文件夹下创建切面类Aspect和需要实现的业务类AspectBiz

在这里插入图片描述

  1. 在Spring-config.xml中声明bean:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd" default-autowire="byType">
    <context:component-scan base-package="test"></context:component-scan>
    <!--<context:property-placeholder location="classpath*:defaltValue"/>-->
        <!--<bean class="test.annotationPractice.dao.InjectDaoConfig" id="injectDaoConfig"></bean>-->
    <!--<property name="userId" value="${defaultId}"/>-->
    <!--</bean>-->
            <bean id="aspect" class="test.aoppractice.Aspect"></bean>
            <bean id="aspectBiz" class="test.aoppractice.AspectBiz"></bean>
    </beans>
    
  2. 接下来,配置aop:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xmlns:context="http://www.springframework.org/schema/context"
           xmlns:aop="http://www.springframework.org/schema/aop"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"
           default-autowire="byType">
    <context:component-scan base-package="test"></context:component-scan>
    <!--<context:property-placeholder location="classpath*:defaltValue"/>-->
        <!--<bean class="test.annotationPractice.dao.InjectDaoConfig" id="injectDaoConfig"></bean>-->
    <!--<property name="userId" value="${defaultId}"/>-->
    <!--</bean>-->
            <bean id="aspect" class="test.aoppractice.Aspect"></bean>
            <bean id="aspectBiz" class="test.aoppractice.AspectBiz"></bean>
        <aop:config>
            <aop:aspect id="aspectAOP" ref="aspect">
    
            </aop:aspect>
        </aop:config>
    </beans>
    

    这样,对于一个切面连接点处理aop就配置好了…

pointcut

​ 切入点:以下是声明例子:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"
       default-autowire="byType">
<context:component-scan base-package="test"></context:component-scan>
<!--<context:property-placeholder location="classpath*:defaltValue"/>-->
    <!--<bean class="test.annotationPractice.dao.InjectDaoConfig" id="injectDaoConfig"></bean>-->
<!--<property name="userId" value="${defaultId}"/>-->
<!--</bean>-->
        <bean id="aspect" class="test.aoppractice.Aspect"></bean>
        <bean id="aspectBiz" class="test.aoppractice.AspectBiz"></bean>
    <aop:config>
        <aop:aspect id="aspectAOP" ref="aspect">
 			<aop:pointcut id="handlerservice" expression="execution(* 					test.BeanNamePractice.*(..))"/>
        </aop:aspect>
       
    </aop:config>
</beans>

上面的pointCcut定义了,只执行BenNamePractice中的所有Service。

Introductions

​ 简介允许一个切面声明一个实现类指定接口的通知对象,并且提供了一个接口实现类来代表这些对象。

声明:

有aop:aspect中的aop:declare-parents元素来声明所匹配的类型拥有一个新的parent,也应此得名。

该方法在getBean获得对象之后强制转成接口。

例子:

首先,声明一个接口:

Fit.java

package test.aopIntroducePractice;

/**
 * @Deprecated  AOP的Introductions的练习
 * @author charlinheng
 * @date 2020年5月24日
 */
public interface Fit {
    void filter();
}

再建立一个实现类

FitImpl.java

package test.aopIntroducePractice;
/**
 * @Deprecated  AOP的Introductions的练习 实现类
 * @author charlinheng
 * @date 2020年5月24日
 */
public class FitImpl implements Fit {
    @Override
    public void filter() {
        System.out.println("Fit的实现类。。。");
    }
}

之后呢,在SPring-config.xml中修改配置如下:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"
       default-autowire="byType">
<context:component-scan base-package="test"></context:component-scan>
        <bean id="aspect" class="test.aoppractice.Aspect"></bean>
        <bean id="aspectBiz" class="test.aoppractice.AspectBiz"></bean>
    <aop:config>
        <aop:aspect id="aspectAOP" ref="aspect">
            <aop:declare-parents types-matching="test.aoppractice.*Biz"
                                 implement-interface="test.aopIntroducePractice.Fit"
                                 default-impl="test.aopIntroducePractice.FitImpl"></aop:declare-parents>
        </aop:aspect>
    </aop:config>
</beans>

接下来在测试类中:

package test;
import org.junit.jupiter.api.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import test.annotationPractice.dao.InjectDaoConfig;
import test.aopIntroducePractice.Fit;

public class TestClass {
    private static final int NUMBER = 3;
    @Test
    public void test(){
        //使用方法1进行添加spring-config文件
        ClassPathXmlApplicationContext classPathXmlApplicationContext =
                new ClassPathXmlApplicationContext("spring-config.xml");
        Fit fit = (Fit) classPathXmlApplicationContext.getBean("aspectBiz");
        fit.filter();
    }
}

在测试类中,将从IOC容器的bean对象集合中获取到的bean的指定对象,然后这个过程中,将会从IOC容器中获取Bean,将这个接口强制转换成指定的父类。

advisors

advisor就像一个小的自包含的方面,只有一个advice,切面自身通过一个bean来表示,并且必须实现某个advice接口,同时,advisor也可以很好的利用AspectJ的切入点表达式。

Spring通过配置文件中aop:advisor元素支持advisor。

Spring AOP Api

在SPring1.2的历史用法中,就已经开始支持了,这是Spring AOp的基础。我们在学习Spring的时候必须要了解

这个知识。

  1. Pointcut

    实现之一:NameMatchMethodPointCut,根据方法名字进行匹配

    例子:

    • ​ 建立AopApiPractice文件夹,如下:

      在这里插入图片描述

    • 在ApoApiPractice文件夹下建立BizLogic接口文件。如下:

      package test.AopApiPractice;
      /**
       * AOP api 练习
       */
      public interface BizLogic {
          String save();
      }
      
    • 接着创建其接口的实现类BbizLoginImpl.java,如下:

      package test.AopApiPractice;
      
      public class BizLogicImpl implements BizLogic {
          @Override
          public String save() {
              System.out.println("实现类的save方法,启动!");
              return "调用了实现类的save方法.";
          }
      }
      
    • 配置切入点: 在Spring-config.xml配置文件中,配置bean,并且分别配置实现类的bean和NameMethodPointCut的bean,如下:

      <?xml version="1.0" encoding="UTF-8"?>
      <beans xmlns="http://www.springframework.org/schema/beans"
             xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xmlns:context="http://www.springframework.org/schema/context"
             xmlns:aop="http://www.springframework.org/schema/aop"
             xsi:schemaLocation="http://www.springframework.org/schema/beans
             http://www.springframework.org/schema/beans/spring-beans.xsd
             http://www.springframework.org/schema/context
             http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"
             default-autowire="byType">
      <context:component-scan base-package="test"></context:component-scan>
              <bean id="bizLoginImplTarget" class="test.AopApiPractice.BizLogicImpl"></bean>
              <bean id="pointcutBean" class="org.springframework.aop.support.NameMatchMethodPointcut">
                  <property name="mappedNames">
                      <list>
                          <value>sa*</value>
                      </list>
                  </property>
              </bean>
          <!--<aop:config>-->
              <!--<aop:aspect id="aspectAOP" ref="aspect">-->
                  <!--<aop:declare-parents types-matching="test.aoppractice.*Biz"-->
                                       <!--implement-interface="test.aopIntroducePractice.Fit"-->
                                       <!--default-impl="test.aopIntroducePractice.FitImpl"></aop:declare-parents>-->
              <!--</aop:aspect>-->
          <!--</aop:config>-->
      </beans>
      

      这样的话,在注册aop的NameMatchMethodPointcut的bean对象时候,他会检测所有含sa*的方法。就会将此符合条件的方法自动检测。

  2. 实例-定义一个前置通知:

    定义MethodBeforeAdvice代码如下:

    package test.AopApiPractice;
    
    import java.lang.reflect.Method;
    
    public class MethodBeforeAdvice implements org.springframework.aop.MethodBeforeAdvice {
        @Override
        public void before(Method method, Object[] objects, Object o) throws Throwable {
            System.out.println("重写 实现前置通知(执行过程):"+method.getName());
        }
    }
    

    ​ 这里要说一下。如果连接点抛出异常,throws advice连接点返回后被调用如throws-advice的方法抛出异常,那么它将覆盖原有异常接口org.springframework.aop.ThrowsAdvice*不包含任何方法,仅仅是一个声明,实现类需要实现类似下面的方法:

    void afterThrowing([Meth0d,args,targetl,ThrowableSubcIass);
    

    可以实现的方式:

    //方式一
    public void afterThrowing(Exceptionex):
    //方式二
    public void afterThrowing(RemoteException ex)//方式三
    public void afterThrowing(Meth0dmethod.Object[] args,Object target,Exception ex);
    //方式四
    public void afterThrowing(Meth0dmethod.Object[] args,Object target,ServletException ex);
    

    举例: 可以通过如下代码实现afterThrowing;

    package test.AopApiPractice;
    /**
    *实现ThrowsAdvice接口-practice
    *@author:charlinheng
    *@date 2020-5-26
    **/
    import java.lang.reflect.Method;
    
    public class ThrowsAdvice implements org.springframework.aop.ThrowsAdvice {
        public void afterThrowing(Exception ex) throws Throwable{
            System.out.println("Throw1...."+ex.getMessage());
        }
        public void afterThrowing(Method method,Exception ex) throws Throwable{
            System.out.println("Throw2...."+ex.getMessage()+","+method.getName());
        }
    }
    
    ProxyFactoryBean

    什么是ProxyFactoryBean呢?

    它是创建Spring AOP代理的基本方法,它存在哪里呢?它存在于

    org.springframework.aop.framework.ProxyFactoryBean

    他能干啥?

    他能完全控制切入点通知他们的顺序

    比如: 声明一个bean名字称为:fooProxyFactoryBean,那么,引用父对象看到的将不是ProxyFactoryBean本身,而是getObject的对象,getObject方法 将 创建一个 AOP代理 包装一个 目标对象 。。

    ProxyFactoryBean就是通过这一种方式来达到代理的目的。

    ProxyFactoryBean的特点

    1.使用ProFactoBean或者其它IoC相关类来创建AOP代理的最重要好处是通知和切入点也可以由IOC来管理

    2.被代理类没有实现任何接口,使用CGLIB代理,否则JDK代理通过设置proxyTargetCIass为true,可强制使用CGLIB

    3.如果目标类实现了一个(或者多个)接口,那么创建代理的类型将依赖ProxyFactoryBean的配置

    4.如RProxyFactoryBean的proxylnterfaces属性被设置为一个或者多个全限定接口名,基于JDK的代理将被创建

    Proxying classes

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值