20_AOP_Advice增强1(前置、后置、环绕)

【增强的类型】

1.前置增强org.springframework.aop.BeforeAdvice

由于Spring只支持方法级别的增强,所以MethodBeforeAdvice是目前可用的前置增强,表示在目标方法执行前执行前置增强,BeforeAdvice是为了将来版本扩展需要而定义的。

2.后置增强org.springframework.aop.AfterReturningAdvice

表示在目标方法执行后执行增强。

3.环绕增强org.aopalliance.intercept.MethodInterceptor

表示在目标方法执行前后执行增强。

4.异常抛出增强org.springframework.aop.ThrowsAdvice

表示在目标方法抛出异常时执行增强。

5.引介增强org.springframework.aop.IntroductionInterceptor

在目标类中添加一些新的属性和方法。

【前置、后置、环绕增强整个工程】

【车子接口 Car.java】

package com.Higgin.part1;

/**
 * 车子接口
 */
public interface Car {
    public void drive();
}

【具体奔驰车类:BenzCar.java】

package com.Higgin.part1;

/**
 * 奔驰车类
 * 我们希望测试奔驰车在执行drive()方法前、后、前后增强的情况
 */
public class BenzCar implements Car{

    @Override
    public void drive() {
        System.out.println("【业务方法】奔驰车在行驶....");
    }

}

【前置增强类】

package com.Higgin.part1;

import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;

/**
 * 前置增强类
 * 实现的是:MethodBeforeAdvice接口
 */
public class DriveBeforeAdvice implements MethodBeforeAdvice{

    /**
     * method:目标类的方法
     *   args:目标类方法的参数
     *    obj:目标类的实例
     */
    @Override
    public void before(Method method, Object[] args, Object obj)throws Throwable {
        System.out.println("【前置增强】开车前自动放音乐~~~");
    }
}

【测试前置增强类1:TestBeforeAdvice】

package com.Higgin.part1.Test;

import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;
import com.Higgin.part1.BenzCar;
import com.Higgin.part1.Car;
import com.Higgin.part1.DriveBeforeAdvice;

/**
 * 测试 前置增强
 */
public class TestBeforeAdvice{
    public static void main(String[] args) {
        Car benz=new BenzCar();        //目标对象
        BeforeAdvice driveBeforeAdvice=new DriveBeforeAdvice(); //前置增强
        
        ProxyFactory pf=new ProxyFactory();  //1.Spring代理工厂
        
        pf.setTarget(benz);                  //2.设置代理目标对象
        
        pf.addAdvice(driveBeforeAdvice);     //3.为代理对象添加增强
        
        Car carProxy=(Car) pf.getProxy();    //4.生成代理实例
        
        carProxy.drive();
        
    }
}

[ 运行结果 ]

【测试前置增强类2:用Spring的xml配置文件方式:TestBeforeAdviceXml.java】

package com.Higgin.part1.Test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.Higgin.part1.Car;

public class TestBeforeAdviceXml {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("part1.xml");
        Car car=(Car) context.getBean("benzCar1");
        car.drive();
    }
}

【测试前置增强类2:用Spring的xml配置文件方式的配置文件:part1.xml】

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
    xmlns:cache="http://www.springframework.org/schema/cache"  
    xsi:schemaLocation="  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context.xsd  
    http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd  
    http://www.springframework.org/schema/tx  
    http://www.springframework.org/schema/tx/spring-tx.xsd  
    http://www.springframework.org/schema/jdbc  
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd  
    http://www.springframework.org/schema/cache  
    http://www.springframework.org/schema/cache/spring-cache-3.1.xsd  
    http://www.springframework.org/schema/aop  
    http://www.springframework.org/schema/aop/spring-aop.xsd  
    http://www.springframework.org/schema/util  
    http://www.springframework.org/schema/util/spring-util.xsd">
    
    <!-- 要增强的目标对象 -->
    <bean id="target" class="com.Higgin.part1.BenzCar"/>
    
    <!-- 前置增强的类 -->
    <bean id="driveBeforeAdvice" class="com.Higgin.part1.DriveBeforeAdvice" />
 
    <!-- Spring代理工厂的成员变量配置(前置增强)-->
    <bean id="benzCar1" class="org.springframework.aop.framework.ProxyFactoryBean"
        p:proxyInterfaces="com.Higgin.part1.Car" 
        p:interceptorNames="driveBeforeAdvice"
        p:target-ref="target"
    />
      
</beans>

[ 运行结果 ]

 【后置增强类:DriveAfterAdvice.java】

package com.Higgin.part1;

import java.lang.reflect.Method;

import org.springframework.aop.AfterReturningAdvice;

/**
 * 后置增强类
 * 实现的是:AfterReturningAdvice
 */
public class DriveAfterAdvice implements AfterReturningAdvice{

    @Override
    public void afterReturning(Object returnObj, Method method, Object[] args, Object obj) throws Throwable {
        System.out.println("【后置增强】停车后自动关闭音乐~~~");
    }
}

【测试后置增强类1:TestAfterAdvice.java】

package com.Higgin.part1.Test;

import org.springframework.aop.AfterReturningAdvice;
import org.springframework.aop.BeforeAdvice;
import org.springframework.aop.framework.ProxyFactory;

import com.Higgin.part1.BenzCar;
import com.Higgin.part1.Car;
import com.Higgin.part1.DriveAfterAdvice;
import com.Higgin.part1.DriveBeforeAdvice;

public class TestAfterAdvice {
    public static void main(String[] args) {
        Car benz=new BenzCar();        //目标对象
        BeforeAdvice driveBeforeAdvice=new DriveBeforeAdvice();         //前置增强
        AfterReturningAdvice driveAfterAdvice=new DriveAfterAdvice();  //后置增强
        
        ProxyFactory pf=new ProxyFactory();  //1.Spring代理工厂
        
        pf.setTarget(benz);                  //2.设置代理目标
        
        pf.addAdvice(driveBeforeAdvice);     //3.为代理对象添加 前 置增强
        pf.addAdvice(driveAfterAdvice);      //3.为代理对象添加 后 置增强
        
        Car carProxy=(Car) pf.getProxy();    //4.生成代理实例
        
        carProxy.drive();
    }
}

【运行结果】

【测试后置增强类2:用Spring的xml配置文件方式:TestAfterAdviceXml.java】

package com.Higgin.part1.Test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.Higgin.part1.Car;

public class TestAfterAdviceXml {
    public static void main(String[] args) {
        ApplicationContext context =new  ClassPathXmlApplicationContext("part1.xml");
        Car benz=(Car) context.getBean("benzCar2");
        benz.drive();
    }
}

【测试后置增强类2:用Spring的xml配置文件方式的配置文件:part1.xml】

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
    xmlns:cache="http://www.springframework.org/schema/cache"  
    xsi:schemaLocation="  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context.xsd  
    http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd  
    http://www.springframework.org/schema/tx  
    http://www.springframework.org/schema/tx/spring-tx.xsd  
    http://www.springframework.org/schema/jdbc  
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd  
    http://www.springframework.org/schema/cache  
    http://www.springframework.org/schema/cache/spring-cache-3.1.xsd  
    http://www.springframework.org/schema/aop  
    http://www.springframework.org/schema/aop/spring-aop.xsd  
    http://www.springframework.org/schema/util  
    http://www.springframework.org/schema/util/spring-util.xsd">
    
    <!-- 要增强的目标对象 -->
    <bean id="target" class="com.Higgin.part1.BenzCar"/>
    
    <!-- 前置增强的类 -->
    <bean id="driveBeforeAdvice" class="com.Higgin.part1.DriveBeforeAdvice" />
    <!-- 后置增强的类 -->
    <bean id="dirveAfterAdvice" class="com.Higgin.part1.DriveAfterAdvice" />

    <!-- Spring代理工厂的成员变量配置(后置增强+前置增强) -->
    <bean id="benzCar2" class="org.springframework.aop.framework.ProxyFactoryBean"
        p:proxyInterfaces="com.Higgin.part1.Car" 
        p:interceptorNames="driveBeforeAdvice,dirveAfterAdvice"
        p:target-ref="target"
    />
    
</beans>

[ 运行结果 ]

【环绕增强类:DriveAroundAdvice.java】

package com.Higgin.part1;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

/**
 * 环绕增强
 * 实现的接口:MethodInterceptor
 * 注意:需要导入jar包:aopalliance-1.0.jar
 */
public class DriveAroundAdvice implements MethodInterceptor{

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("【前置增强】开车前自动打开音乐~~~");
        Object obj=invocation.proceed();  //通过反射执行目标的业务方法
        System.out.println("【后置增强】停车后自动关闭音乐~~~");
        return obj;
    }

}

【环绕增强测试类1:TestAroundAdvice.java】

package com.Higgin.part1.Test;

import org.aopalliance.intercept.MethodInterceptor;
import org.springframework.aop.framework.ProxyFactory;

import com.Higgin.part1.BenzCar;
import com.Higgin.part1.Car;
import com.Higgin.part1.DriveAroundAdvice;

public class TestAroundAdvice {
    public static void main(String[] args) {
        Car benzCar=new BenzCar();
        MethodInterceptor driveAroundAdvice=new DriveAroundAdvice();
        
        ProxyFactory pf=new ProxyFactory();
        
        pf.setTarget(benzCar);
        
        pf.addAdvice(driveAroundAdvice);
        
        Car carProxy=(Car) pf.getProxy();
        
        carProxy.drive();
    }
}

[ 运行结果 ]

【测试环绕增强类2:用Spring的xml配置文件方式:TestAroundAdviceXml.java】

package com.Higgin.part1.Test;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.Higgin.part1.Car;

public class TestAroundAdviceXml {
    public static void main(String[] args) {
        ApplicationContext context=new ClassPathXmlApplicationContext("part1.xml");
        Car car=(Car) context.getBean("benzCar3");
        car.drive();
    }
}

【测试环绕增强类2:用Spring的xml配置文件方式的配置文件:part1.xml】

<?xml version="1.0" encoding="UTF-8"?>  
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"  
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p" xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"  
    xmlns:cache="http://www.springframework.org/schema/cache"  
    xsi:schemaLocation="  
    http://www.springframework.org/schema/context  
    http://www.springframework.org/schema/context/spring-context.xsd  
    http://www.springframework.org/schema/beans  
    http://www.springframework.org/schema/beans/spring-beans.xsd  
    http://www.springframework.org/schema/tx  
    http://www.springframework.org/schema/tx/spring-tx.xsd  
    http://www.springframework.org/schema/jdbc  
    http://www.springframework.org/schema/jdbc/spring-jdbc-3.1.xsd  
    http://www.springframework.org/schema/cache  
    http://www.springframework.org/schema/cache/spring-cache-3.1.xsd  
    http://www.springframework.org/schema/aop  
    http://www.springframework.org/schema/aop/spring-aop.xsd  
    http://www.springframework.org/schema/util  
    http://www.springframework.org/schema/util/spring-util.xsd">
    
    <!-- 要增强的目标对象 -->
    <bean id="target" class="com.Higgin.part1.BenzCar"/>
    
    <!-- 环绕增强的类 -->
    <bean id="driveAroundAdvice" class="com.Higgin.part1.DriveAroundAdvice"/>
 
    <!-- Spring代理工厂的成员变量配置(环绕增强) -->
    <bean id="benzCar3" class="org.springframework.aop.framework.ProxyFactoryBean"
        p:proxyInterfaces="com.Higgin.part1.Car" 
        p:interceptorNames="driveAroundAdvice"
        p:target-ref="target"
    />
   
</beans>

[ 运行结果 ]

【分析】

1.关于spring的xml配置文件的分析

其中的ProxyFactoryBean类是FactoryBean的实现类,

FactoryBean负责实例化一个Bean,

ProxyFactoryBean负责为其他Bean创建代理实例,它内部使用ProxyFactory来完成这一工作。

ProxyFactoryBean的几个可配置属性(成员变量)

  target:代理的目标对象

  proxyInterfaces:代理需要实现的接口,可以是多个接口。该属性该有一个别名interfaces。

  interceptor:需要织入目标对象的Bean列表。采用Bean的名称指定。这些Bean必须是实现了org.aoplliance.interceptor.MethodInterceptor或者org.springframework.Advisor的Bean,配置中的顺序对应调用的顺序。

  singleton:返回的代理是否是单例,默认单例。

  optimize:为true时,强制使用Cglib代理,对于Singleton的代理,建议使用CGlib。对于其他作用域类型的代理,最好使用JDK代理。(CGLib创建代理时速度慢,而创建出来的代理对象运行效率高,JDK代理相反)

  proxyTargetClass:是否对类进行代理(而不是对接口进行代理),设置为true时,使用CGLib代理。

  

原文地址:https://www.cnblogs.com/HigginCui/p/6309035.html