Spring AOP

静态代理与动态代理:

代理模式的定义是:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理设计模式可以在不改变原始代码

静态代理的实现:

 ISendBook接口

public interface ISendBook {
    public void sendBook();
}

 DangDang类,继承ISendBook接口:

public class DangDang implements ISendBook{

    @Override
    public void sendBook() {
        // TODO Auto-generated method stub
        System.out.println("当当网-书籍部门,将书送到指定地址的客户手中");
    }
}

 SFSendBookProxy类,继承ISendBook的另外一个接口

public class SFSendBookProxy implements ISendBook{
    
    public ISendBook sendBook;
    
    public SFSendBookProxy(ISendBook sendBook){
        super();
        this.sendBook = sendBook;
    }
    
    @Override
    public void sendBook() {
        // TODO Auto-generated method stub
        System.out.println("顺丰接收书籍");
        sendBook.sendBook();
        System.out.println("顺丰书籍已送达");
    }
}

 AopTest类

public class AopTest {
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        ISendBook sendBook = new SFSendBookProxy(new DangDang());
        sendBook.sendBook();
    }
}

 运行结果:

顺丰接收书籍
当当网-书籍部门,将书送到指定地址的客户手中
顺丰书籍已送达

 上述代码实现了静态的代理,在改变原有的DangDang类的同时,对其方法进行了增加内容/功能。但这种代理有个致命的缺点,就是要创建一个类,并且这个类要继承与要增加增加功能的类一致的接口,由于与接口绑死,不利于扩张。因此有了下面的动态代理。

 接口与DangDang类保持不变,创建一个类继承InvocationHandler接口:

public class SendBookInvocationHandler implements InvocationHandler{
    private Object object;
    public SendBookInvocationHandler(Object object){
        super();
        this.object = object;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("顺丰接收书籍");
        Object returnValue = method.invoke(object,args);
        System.out.println("顺丰配出书籍");
        return returnValue;
    }
}

 更改AopTest类main方法的内容:

  public static void main(String[] args) {
        DangDang dangdang = new DangDang();
        ISendBook sendBook = (ISendBook) Proxy.newProxyInstance(AopTest.class.getClassLoader(),
        dangdang.getClass().getInterfaces(),new SendBookInvocationHandler(dangdang));
        sendBook.sendBook();
    }

 运行结果:

顺丰接收书籍
当当网-书籍部门,将书送到指定地址的客户手中
顺丰配出书籍

 同样实现了对DangDang的sendBook方法增强了内容/功能。但这种方式仅仅只用继承唯一指定的接口便可以实现,而不是要继承与类一致的接口。有利于扩展。

  尽管原生态SDK的动态代理能实现功能,但还是不太方便,并且每个程序员的写法会不同,不利于代码风格的一致性与后期维护,因此使用了Spring框架对动态代理进行了封装,方便与维护。

  1. 方法前通知要实现MethodBeforeAdvice接口

  2. 方法后通知要实现AfterReturningAdvice接口

  3. 方法环绕通知要实现MethodInterceptor接口

  4. 异常处理通知要实现 ThrowsAdvice接口

 对上述进行Spring进行动态代理:

  ISendBook接口以及DangDang类不用修改

  添加AfterSentBook类:该类继承了AfterReturningAdvice接口

public class AfterSentBook implements AfterReturningAdvice{

    //Object arg0:返回值
    //Method arg1:方法对象
    //Object[] arg2:参数
    //Object arg3:原始目标被功能增强的对象
    @Override
    public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("AftrSentBook信息,返回值:"+arg0+",方法名称:"+arg1+",方法参数个数:"+arg2.length+
                ",原始对象:"+arg3);
    }
}

  添加BeforeSendBook类:该类继承了MethodBeforAdvice接口

public class BeforeSendBook implements MethodBeforeAdvice{
    //Method arg0 :方法对象
    //Object[] arg1: 方法的参数值
    //Object arg2:原始目标被功能增强的对象
    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("BeforeSendBook信息,方法名称="+arg0.getName()+",参数个数:"+arg1.length+",原始对象:"+arg2);
    }
}

  该类继承了MethodTnterceptor接口

public class RoundSentBook implements MethodInterceptor{
    /**
     * MethodInvocation arg0:类的对象,可以通过此对象,调用以下的方法
     * getArguments(): 获取参数
     * getMethod(): 获取方法对象
     * getThis(): 原始目标被功能增强的对象
     * proceed():调用原始目标对象的指定Method方法,并返回原始目标对象
     * */
    @Override
    public Object invoke(MethodInvocation arg0) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("MethodInterceptor begin信息,方法名称="+arg0.getMethod().getName()+
                "参数个数:"+arg0.getArguments()+",原始对象:"+arg0.getThis());
        Object object = arg0.proceed();
        System.out.println("MethodInterceptor end信息,方法名称="+arg0.getMethod().getName()+
                "参数个数:"+arg0.getArguments()+",原始对象:"+arg0.getThis());
        return object;
    }    
}

  xml配置文件:

<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:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="dangdang" class="Spring.DangDang"></bean>
    <bean id="before" class="Spring.BeforeSendBook"></bean>
    <bean id="after" class="Spring.AfterSentBook"></bean>
    <bean id="round" class="Spring.RoundSentBook"></bean>
    <bean id="error" class="Spring.My_ThrowsAdvice"></bean>
    
    <!--  -->
    <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="interfaces">
            <list>
                <value>Spring.ISendBook</value>
            </list>
        </property>
        <property name="target" ref="dangdang"></property>
        <property name="interceptorNames">
            <list>
                <value>round</value>
                <value>before</value>
                <value>after</value>
            </list>
        </property>
    </bean>
</beans>

  AopTest类:

public class AopTest {

    public static void main(String[] args) {    
        ApplicationContext context = new ClassPathXmlApplicationContext("aop-applicationContext.xml");
        ISendBook sendBook = (ISendBook)context.getBean("proxy");
        sendBook.sendBook();
    }
}

  运行结果如下:

MethodInterceptor begin信息,方法名称=sendBook参数个数:[Ljava.lang.Object;@63e2203c,原始对象:Spring.DangDang@1efed156
BeforeSendBook信息,方法名称=sendBook,参数个数:0,原始对象:Spring.DangDang@1efed156
当当网-书籍部门,将书送到指定地址的客户手中
AftrSentBook信息,返回值:null,方法名称:public abstract void Spring.ISendBook.sendBook(),方法参数个数:0,原始对象:Spring.DangDang@1efed156
MethodInterceptor end信息,方法名称=sendBook参数个数:[Ljava.lang.Object;@6737fd8f,原始对象:Spring.DangDang@1efed156

 

 我们可以看到Spring对动态代理进行了封装,但是这种方式一个通用业务需要创建4个类,方法执行前,方法执行后,方法环绕,以及出现异常的情况,假设如果有很多个通用业务,那么就需要创建4*对应通用业务数,尽管有效的对动态代理进行了有效的封装,但如果通用业务多的话,管理起来还是比较复杂,因此Spring 推出了AOP的方式来实现。

 

Spring的AOP:

 要知道,Spring的AOP技术原理就是基于代理设计模式的。因此当Spring使用AOP技术的时候,运行的效果往往与动态代理的效果是很类似,或者是是一摸一样的。

 在学习AOP技术之前,首先需要了解几个概念:

  1. 横切关注点

  2.切面

  3. 连接点

  4. 切点

  5. 通知:通知便是定义了在什么时机进行切莫的参数,在Spring的AOP的通知中,分为5种:

   前置通知(Before):方法被调用前

   后置通知(After):方法被调用后

   环绕通知(Around):方法被调用之前与之后

   返回通知(After-returning):方法返回了值后执行

   异常处理(After-throwing):当执行方法中出现异常后触发执行

  6. 织入

 

 与DI容器/IOC技术一样,Spring实现aop技术也可以分全xml与全注解的形式。它们实现的功能都是相同的,只是编写的形式不一样。

  使用xml方式 DangDang类:

public class DangDang{
    
    boolean isGet = false;
    
    public void bookBooks(){
        System.out.println("当当网-书籍部门,客户订书了");
    }
    
    public void sendBook() {
        // TODO Auto-generated method stub
        System.out.println("当当网-书籍部门,将书送到指定地址的客户手中");
    }
    
    public boolean isGetBook(){
        System.out.println("客户是否收到书籍");
        return isGet;
    }
}

  使用xml方式:AspectObject类

public class AspectObject {
    public void beginRun(){
        System.out.println("前置通知------------");
    }
    
    public void endRun(){
        System.out.println("后置通知------------");
    }
    
    public Object round(ProceedingJoinPoint point){
        System.out.println("前");
        Object returnObject = null;
        try {
            returnObject = point.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("后");
        return returnObject;
    }
    
    @AfterReturning("execution(* Spring.DangDang.* (..))")
    public void afterRun(){
        System.out.println("返回值通知------------");
    }
    
    public void afterThrowing(){
        System.out.println("异常通知------------");
    }
}

  使用xml方式:aop-applicationConfig.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:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="dangdang" class="Spring.DangDang"></bean>
    <bean id="aspectObject" class="Spring.AspectObject"></bean>

    <aop:config>
        <aop:aspect ref="aspectObject">
            <aop:before method="beginRun" pointcut="execution(* Spring.DangDang.bookBooks(..))"/>
            <aop:after method="endRun" pointcut="execution(* Spring.DangDang.bookBooks(..))"/>
            <aop:around method="round" pointcut="execution(* Spring.DangDang.sendBook(..))"/>
            <aop:after-returning method="afterRun" pointcut="execution(* Spring.DangDang.isGetBook(..))"/>
            <aop:after-throwing method="afterThrowing" pointcut="execution(* Spring.DangDang.*(..))"/>
        </aop:aspect>
    </aop:config>
</beans>

  使用了xml方式:AopTest类

public class AopTest {

    public static void main(String[] args) {
        
        ApplicationContext context = new ClassPathXmlApplicationContext("aop-applicationContext.xml");
        DangDang dangdang = (DangDang) context.getBean("dangdang");
        dangdang.bookBooks();
        System.out.println();
        dangdang.sendBook();
        System.out.println();
        dangdang.isGetBook();
            
    }
}

  运行结果如下:

前置通知------------
当当网-书籍部门,客户订书了
后置通知------------

前
当当网-书籍部门,将书送到指定地址的客户手中
后

客户是否收到书籍
返回值通知------------

    

  使用注解的方式,DangDang类:

@Component(value="dangdang1")
public
class DangDang{ boolean isGet = false; public void bookBooks(){ System.out.println("当当网-书籍部门,客户订书了"); } public void sendBook() { // TODO Auto-generated method stub System.out.println("当当网-书籍部门,将书送到指定地址的客户手中"); } public boolean isGetBook(){ System.out.println("客户是否收到书籍"); return isGet; } }

  使用注解的方式,AspectObject类:

@Component
@Aspect  //必须填写,不然不知道切面要执行的执行体
public class AspectObject {
    @Before(value="execution(* Spring.DangDang.bookBooks(..))")
    public void beginRun(){
        System.out.println("前置通知------------");
    }
    
    @After(value="execution(* Spring.DangDang.bookBooks(..))")
    public void endRun(){
        System.out.println("后置通知------------");
    }
    
    @Around(value="execution(* Spring.DangDang.sendBook(..))")
    public Object round(ProceedingJoinPoint point){
        System.out.println("前");
        Object returnObject = null;
        try {
            returnObject = point.proceed();
        } catch (Throwable e) {
            e.printStackTrace();
        }
        System.out.println("后");
        return returnObject;
    }
    
    @AfterReturning(value="execution(* Spring.DangDang.isGetBook (..))")
    public void afterRun(){
        System.out.println("返回值通知------------");
    }
    
    @AfterThrowing(value="publicPointcut() and bean(dangdang1)")
    public void afterThrowing(){
        System.out.println("异常通知------------");
    }
}

  使用注解的方式,AopTest类:

@EnableAspectJAutoProxy   //必须填写,如无该注解的话,AspectObject类仅仅只是一个普通的类,有该注解,AspectObject才能算的上是切面
@ComponentScan(basePackages="Spring")
public class AopTest {

    public static void main(String[] args) {
        
        String resource = "Spring";
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopTest.class);
        DangDang dangdang = (DangDang) context.getBean("dangdang1");
        dangdang.bookBooks(null);
        System.out.println();
        dangdang.sendBook(null,null);
        System.out.println();
        dangdang.isGetBook();
    }
}

  运行效果与使用xml方式的运行效果一致。

 

 看到上述使用xml方式与注解方式,最主要的是execution(* Spring.DangDang.bookBooks(..))的表达式,该表达式对应的参数如下:

  第一个代表的是返回值,* 代表任意的返回值

  第二个代表的是指定包下的指定类下的指定方法下的指定参数,Spring.DangDang.bookBooks(..) ,代表的是Spring包下的DangDang类下的bookBooks方法,使用的是任意的bookBooks的参数。括号中代表的是对应方法的参数,每个方法的参数都不一致,因此可以用..来代替任意的参数。若想调用该类的全部方法:Spring.DangDang.*(..)

 可以看到前置与后置的切点都是一致的,为了减少execution表达式,降低冗余的配置,可以将execution表达式进行全局化:

  对应xml方式,改动aop-applicationConfig.xml文件:

<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:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="dangdang" class="Spring.DangDang"></bean>
    <bean id="aspectObject" class="Spring.AspectObject"></bean>

    <aop:config>
        <!-- 定义全局切点 -->
        <aop:pointcut id="pointcut1" expression="execution(* Spring.DangDang.bookBooks(..))"/>
        <aop:pointcut id="pointcut2" expression="execution(* Spring.DangDang.* (..))" />
        <aop:aspect ref="aspectObject">        
            <aop:before method="beginRun" pointcut-ref="pointcut1"/>
            <aop:after method="endRun" pointcut-ref="pointcut1"/>
            <aop:around method="round" 
                pointcut="execution(* Spring.DangDang.sendBook(..))"/>
            <aop:after-returning method="afterRun" pointcut="execution(* Spring.DangDang.isGetBook(..))"/>
            <aop:after-throwing method="afterThrowing"/>
        </aop:aspect>
    </aop:config>
</beans>

  修改后运行AopTest类:运行效果一致

 

  对应注解的方式,仅改动AspectObject类:

@Component
@Aspect  //必须填写,不然不知道切面要执行的执行体
public class AspectObject {
   @Pointcut(value="execution(* Spring.DangDang.bookBooks(..))")
   public void publicPointcut(){}
@Before(value
="publicPointcut()") public void beginRun(){ System.out.println("前置通知------------"); } @After(value="publicPointcut()") public void endRun(){ System.out.println("后置通知------------"); } @Around(value="execution(* Spring.DangDang.sendBook(..))") public Object round(ProceedingJoinPoint point){ System.out.println("前"); Object returnObject = null; try { returnObject = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("后"); return returnObject; } @AfterReturning(value="execution(* Spring.DangDang.isGetBook (..))") public void afterRun(){ System.out.println("返回值通知------------"); } @AfterThrowing(value="publicPointcut() and bean(dangdang1)") public void afterThrowing(){ System.out.println("异常通知------------"); } }

  修改后运行AopTest类:运行效果一致

 

 向切面传入参数值:

  如果方法中有参数,切面类也可以接收这个参数,并可以进行预处理。在5种通知中,对于获取方法参数重要的是前置,后置与绕环的通知种类;而返回通知,是获取方法的返回值,异常通知,则是获取方法中出现的异常。

  使用xml的方式,DangDang类:对方法中添加了参数

@Component(value="dangdang1")
public class DangDang{
    
    boolean isGet = false;
    
    public void bookBooks(Integer userId){
        System.out.println("当当网-书籍部门,客户订书了");
    }
    
    public void sendBook(Integer userId,Integer orderId) {
        // TODO Auto-generated method stub
        System.out.println("当当网-书籍部门,将书送到指定地址的客户手中");
    }
    
    public boolean isGetBook(){
        System.out.println("客户是否收到书籍");
        return isGet;
    }
}

  使用xml的方式,AspectObject类:

public class AspectObject {

   //切面类的方法参数要与对应方法的参数(包括参数的数据类型以及参数名)一致,从而可以获取方法的参数 public void beginRun(Integer userId){ if(userId != null){ System.out.println("客户已登录,userId号为:"+userId); }else{ System.out.println("客户未登陆,已让客户去登录"); userId = 12; System.out.println("客户登录成功,userId号为:"+userId); } } public Integer endRun(Integer userId){ Integer orderId = 120; System.out.println("已生成订单,订单号为:"+orderId); return orderId; } public Object round(ProceedingJoinPoint point,Integer userId,Integer orderId){ System.out.println("前,userId:"+userId+",orderId:"+orderId); Object returnObject = null; try { returnObject = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("后,userId:"+userId+",orderId:"+orderId); return returnObject; } public void afterRun(boolean isGet){ System.out.println("返回值通知------------"); if(isGet){ System.out.println("客户已收到"); }else{ System.out.println("客户未收到"); } }

public void afterThrowing(Throwable t){ System.out.println("异常通知------------"); System.out.println("aopThrowMethod t="+t.getMessage()); } }

  使用xml方式,aop-applicationConfig.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:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <bean id="dangdang1" class="Spring.DangDang"></bean>
    <bean id="aspectObject" class="Spring.AspectObject"></bean>

    <aop:config>
        <!-- 定义全局切点 -->
        <!-- 全部变量,execution表达式中方法名后面的括号填写参数的数据类型,按照方法的参数顺序填写,
              在exectution表达式后跟着的是对应方法参数的值,注意的是,一定要用and来连接起来,否则会出错 -->
        <aop:pointcut id="pointcut1" expression="execution(* Spring.DangDang.bookBooks(Integer)) and args(userId)"/>
        <aop:pointcut id="pointcut2" expression="execution(* Spring.DangDang.* (..))" />
        <aop:aspect ref="aspectObject">        
            <aop:before method="beginRun" pointcut-ref="pointcut1"/>
            <aop:after method="endRun" pointcut-ref="pointcut1"/>
            <aop:around method="round" 
                pointcut="execution(* Spring.DangDang.sendBook(Integer,Integer)) and args(userId,orderId)"/>
            <aop:after-returning method="afterRun" pointcut="execution(* Spring.DangDang.isGetBook(..))" 
                returning="isGet"/> <-- 返回通知,获取方法的返回值,returning的值与方法返回的值名称是一致的-->
        
       <-- 异常通知,获取方法执行中的异常状态,throwing的方法 -->
<aop:after-throwing method="afterThrowing" pointcut-ref="pointcut2" throwing="t"/> </aop:aspect> </aop:config> </beans>

  AopTest类:

public class AopTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("aop-applicationContext.xml");
        DangDang dangdang = (DangDang) context.getBean("dangdang1");
        dangdang.bookBooks(1);
        System.out.println();
        dangdang.sendBook(1,120);
        System.out.println();
        dangdang.isGetBook();
    }
}

  运行效果如下:

客户已登录,userId号为:1
当当网-书籍部门,客户订书了
已生成订单,订单号为:120

前,userId:1,orderId:120
当当网-书籍部门,将书送到指定地址的客户手中
后,userId:1,orderId:120

客户是否收到书籍
返回值通知------------
客户未收到

  

  使用注解的方式,DangDang类:

@Component(value="dangdang1")
public class DangDang{
    
    boolean isGet = false;
    
    public void bookBooks(Integer userId){
        System.out.println("当当网-书籍部门,客户订书了");
    }
    
    public void sendBook(Integer userId,Integer orderId) {
        // TODO Auto-generated method stub
        System.out.println("当当网-书籍部门,将书送到指定地址的客户手中");
    }
    
    public boolean isGetBook(){
        System.out.println("客户是否收到书籍");
        return isGet;
    }
}

  使用注解的方式,AspectObject类:

@Component
@Aspect
public class AspectObject {
    
   //与xml的value值是一致的 @Pointcut(value="execution(* Spring.DangDang.bookBooks(Integer)) && args(userId)") public void publicPointcut1(Integer userId){} @Pointcut(value="execution(* Spring.DangDang.* (..))") public void publicPointcut(){} @Before(value="publicPointcut1(userId)") public void beginRun(Integer userId){ if(userId != null){ System.out.println("客户已登录,userId号为:"+userId); }else{ System.out.println("客户未登陆,已让客户去登录"); userId = 12; System.out.println("客户登录成功,userId号为:"+userId); } } @After(value="publicPointcut1(userId)") public Integer endRun(Integer userId){ Integer orderId = 120; System.out.println("已生成订单,订单号为:"+orderId); return orderId; } @Around(value="execution(* Spring.DangDang.sendBook(Integer,Integer)) && args(userId,orderId)") public Object round(ProceedingJoinPoint point,Integer userId,Integer orderId){ System.out.println("前,userId:"+userId+",orderId:"+orderId); Object returnObject = null; try { returnObject = point.proceed(); } catch (Throwable e) { e.printStackTrace(); } System.out.println("后,userId:"+userId+",orderId:"+orderId); return returnObject; } //返回通知,是获取方法返回值 @AfterReturning(value="execution(* Spring.DangDang.isGetBook (..))",returning="isGet") public void afterRun(boolean isGet){ System.out.println("返回值通知------------"); if(isGet){ System.out.println("客户已收到"); }else{ System.out.println("客户未收到"); } } //异常通知,是获取方法中出现错误的异常
   @AfterThrowing(value="publicPointcut() and bean(dangdang1)",throwing="t") public void afterThrowing(Throwable t){ System.out.println("异常通知------------"); System.out.println("aopThrowMethod t="+t.getMessage()); } }

  使用注解的方法,AopTest类:

@EnableAspectJAutoProxy
@ComponentScan(basePackages="Spring")
public class AopTest {

    public static void main(String[] args) {
        
        String resource = "Spring";
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AopTest.class);
        DangDang dangdang = (DangDang) context.getBean("dangdang1");
        dangdang.bookBooks(null);
        System.out.println();
        dangdang.sendBook(null,null);
        System.out.println();
        dangdang.isGetBook();
    }
}

  运行AopTest类,运行效果如下:

客户未登陆,已让客户去登录
客户登录成功,userId号为:12
当当网-书籍部门,客户订书了
已生成订单,订单号为:120

前,userId:null,orderId:null
当当网-书籍部门,将书送到指定地址的客户手中
后,userId:null,orderId:null

客户是否收到书籍
返回值通知------------
客户未收到

   

  使用半注解半xml的形式:

   使用上述注解方式的AsceptObject与DangDang类

   使用上述xml方式的AopTest类

   改变aop-applicationConfig.xml文件:

<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:c="http://www.springframework.org/schema/c"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/util
        http://www.springframework.org/schema/util/spring-util.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 使用全包搜索 -->
    <context:component-scan base-package="Spring"></context:component-scan>
    
    <!-- 使用aop:aspectj-autoproxy标签根据类中的注解来自动完成切点 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

  运行AopTest类,运行效果如下:

客户已登录,userId号为:1
当当网-书籍部门,客户订书了
已生成订单,订单号为:120

前,userId:1,orderId:120
当当网-书籍部门,将书送到指定地址的客户手中
后,userId:1,orderId:120

客户是否收到书籍
返回值通知------------
客户未收到

 

posted @ 2019-09-07 16:41  HJLのH  阅读(189)  评论(0编辑  收藏  举报