Spring-AOP用法总结

前言

    Spring AOP的实现方法很多,在项目开发中具体采用什么方式,需要按实际情况来选择,每一种的用法,有其一定的实用价值,所以本文将各种使用方法进行了具体实现。主要包括Advice的before、after、throwing、around四种拦截方式的实现,如何进行正则匹配,自动化代理及AspectJ注解形式的实现。

AOP的定义

Spring AOP(Aspect-oriented programming) 面向切面编程,是一种特殊的拦截器,将一组程序中的公共部分抽离出来进行单独管理,降低程序的耦合度,aop和oo互为补充,面向对象编程将程序分解成各个层次的对象,而面向切面编程将程序运行过程分解成各个切面。也可以这样理解,面向对象编程是从静态角度考虑程序结构,面向切面编程是从动态角度考虑程序运行过程。

AOP中6个要素

(1)通知(增强)Advice

  通知定义了切面是什么以及何时使用,应该应用在某个方法被调用之前?之后?还是抛出异常时?等等。

(2)连接点 Join point

  连接点是在应用执行过程中能够插入切面的一个点。这个点可以是调用方法时,抛出异常时,甚至修改一个字段时。切面代码可以利用这些点插入到应用的正常流程中,并添加新的行为。

(3)切点 Pointcut

  切点有助于缩小切面所通知的连接点的范围。如果说通知定义了切面的“什么”和“何时”的话,那么切点就定义了“何处”,切点会匹配通知所要织入的一个或多个连接点,一般常用正则表达式

定义所匹配的类和方法名称来指定这些切点。

(4)切面 Aspect

  切面是通知和切点的结合。通知和切点定义了切面的全部内容——它是什么,在何时何处完成其功能。

(5)引入 Introduction

  引入允许我们向现有的类添加新方法或属性,从而无需修改这些现有类的情况下,让他们具有新的行为和状态。

(6)织入 Weaving

  在过去我常常把织入与引入的概念混淆,我是这样来辨别的,“引入”我把它看做是一个定义,也就是一个名词,而“织入”我把它看做是一个动作,一个动词,也就是切面在指定的连接点被织

入到目标对象中。

AOP用法总结

(1)Before advice 在方法执行前执行。

(2)After  returning  advice 在方法执行后返回一个结果后执行。

(3)After  throwing advice 在方法执行过程中抛出异常的时候执行。

(4)Around  advice 在方法执行前后和抛出异常时执行,相当于综合了以上三种通知。

(5)基于正则表达式,对符合匹配规则类或方法进行拦截处理。

(6)基于自动代理,简少配置。

(7)基于AspectJ注解形式,包括execution 表达式、@DeclareParents 注解、自动代理。

实例

1. Before advice 在方法执行前执行

创建Product产品类

 1 package com.jk.work.aopone;
 2 /**
 3  * Title: 产品
 4  * Description: 该类的功能
 5  *
 6  * @author jihuan
 7  * @create 2017-05-18
 8  * @version: 1.0
 9  */
10 public class Product {
11     private  String  name;
12     private  String  type;
13     private   int    size;
14
15     public String getName() {
16         return name;
17     }
18
19     public void setName(String name) {
20         this.name = name;
21     }
22
23     public String getType() {
24         return type;
25     }
26
27     public void setType(String type) {
28         this.type = type;
29     }
30
31     public int getSize() {
32         return size;
33     }
34
35     public void setSize(int size) {
36         this.size = size;
37     }
38
39     public  void  printName(){
40         System.out.println("Product name "+ this.name);
41     }
42
43     public  void  printType(){
44         System.out.println("Product type "+this.type);
45     }
46
47     public  void  printThrowException(){
48         throw  new  IllegalArgumentException();
49     }
50 }

创建BeforeMethod类

 1 package com.jk.work.aopone;
 2 import org.springframework.aop.MethodBeforeAdvice;
 3 import java.lang.reflect.Method;
 4 /**
 5  * Title: BeforeMethod
 6  * Description: 在方法执行前执行
 7  *
 8  * @author jihuan
 9  * @create 2017-05-19
10  * @version: 1.0
11  */
12 public class BeforeMethod implements MethodBeforeAdvice {
13     @Override
14     public void before(Method method, Object[] objects, Object o) throws Throwable {
15         System.out.println("Before  Method");
16         System.out.println("--------------------");
17     }
18 }

创建配置文件

<?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-3.0.xsd">

    <bean id="product" class="com.jk.work.aopone.Product">
        <property name="name" value="p2p p2p p2p" />
        <property name="type" value="one year"/>
        <property name="size" value="30000" />
    </bean>

    <bean id="beforeMethodBean" class="com.jk.work.aopone.BeforeMethod" />

    <bean id="productProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="product"/>
        <property name="interceptorNames">
            <list>
                <value>beforeMethodBean</value>
            </list>
        </property>
        <property name="proxyTargetClass" value="true"/> <!-- true 表 cglib,false 为jdkproxy(需要property 引入接口)-->
    </bean>
</beans>

创建测试类Test.java

package com.jk.work.aopone;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Title: 类的主题(开发人员填写)
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-19
 * @version: 1.0
 */
public class Test {

    public static void main(String[] args) {
        ApplicationContext context  = new ClassPathXmlApplicationContext("classpath:spring/spring-aop.xml");
        Product   product  =   (Product) context.getBean("productProxy");
        System.out.println("---------------------");
        product.printName();
        System.out.println("---------------------");
        product.printType();
        System.out.println("----------------------");
        try{
            product.printThrowException();
        }catch(Exception e){
        }
    }
}

运行结果:

---------------------
Before  Method
--------------------
Product name p2p p2p p2p
---------------------
Before  Method
--------------------
Product type one year
----------------------
Before  Method
--------------------

测试类可以采用编程式调用,简单实现:

package com.jk.work.aopone;
import org.springframework.aop.framework.ProxyFactory;
/**
 * Title: 编程式
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-19 00:26
 * @version: 1.0
 */
public class Test2 {

    public static void main(String[] args) {
        ProxyFactory proxyFactory=new ProxyFactory() ;
        Product product1=new Product();
        product1.setName("p2p");
        proxyFactory.setTarget(product1);
        proxyFactory.addAdvice(new BeforeMethod());
        Product product=(Product)proxyFactory.getProxy();
        product.printName();
    }
}

运行结果:

Before  Method
--------------------
Product name p2p

2.After  returning  advice 方法之后执行

创建AfterMethod类

 1 package com.jk.work.aopone;
 2 import org.springframework.aop.AfterReturningAdvice;
 3 import java.lang.reflect.Method;
 4 /**
 5  * Title: 类的主题(开发人员填写)
 6  * Description: 该类的功能
 7  *
 8  * @author jihuan
 9  * @create 2017-05-19 00:09
10  * @version: 1.0
11  */
12 public class AfterMethod implements AfterReturningAdvice {
13     @Override
14     public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
15         System.out.println("-------------------");
16         System.out.println("After  method ");
17     }
18 }

创建配置文件

<?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-3.0.xsd">

    <bean id="product" class="com.jk.work.aopone.Product">
        <property name="name" value="p2p p2p p2p" />
        <property name="type" value="one year"/>
        <property name="size" value="30000" />
    </bean>

    <bean id="afterMethodBean" class="com.jk.work.aopone.AfterMethod" />

    <bean id="productProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="product"/>
        <property name="interceptorNames">
            <list>
                <value>afterMethodBean</value>
            </list>
        </property>
        <property name="proxyTargetClass" value="true"/> <!-- true 表 cglib,false 为jdkproxy(需要property 引入接口)-->
    </bean>
</beans> 

创建测试类复用Test.java

运行结果:

---------------------
Product name p2p p2p p2p
-------------------
After  method
---------------------
Product type one year
-------------------
After  method
----------------------

3. After  throwing advice 在方法执行过程中抛出异常的时候执行

创建ThrowException类

 1 package com.jk.work.aopone;
 2 import org.springframework.aop.ThrowsAdvice;
 3 /**
 4  * Title: 类的主题(开发人员填写)
 5  * Description: 该类的功能
 6  *
 7  * @author jihuan
 8  * @create 2017-05-19
 9  * @version: 1.0
10  */
11 public class ThrowException  implements ThrowsAdvice {
12     public  void  afterThrowing(IllegalArgumentException e)  throws  Throwable{
13         System.out.println("after Throwing  Exception");
14     }
15 }

创建配置文件

<?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-3.0.xsd">

    <bean id="product" class="com.jk.work.aopone.Product">
        <property name="name" value="p2p p2p p2p" />
        <property name="type" value="one year"/>
        <property name="size" value="30000" />
    </bean>

    <bean id="throwException" class="com.jk.work.aopone.ThrowException" />

    <bean id="productProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="product"/>
        <property name="interceptorNames">
            <list>
                <value>throwException</value>
            </list>
        </property>
        <property name="proxyTargetClass" value="true"/> <!-- true 表 cglib,false 为jdkproxy(需要property 引入接口)-->
    </bean>
</beans>

运行结果

---------------------
Product name p2p p2p p2p
---------------------
Product type one year
----------------------
after Throwing  Exception

4. Around  advice 在方法执行前后和抛出异常时执行,相当于综合了以上三种通知 

创建AroundMethod类

 1 package com.jk.work.aopone;
 2 import org.aopalliance.intercept.MethodInterceptor;
 3 import org.aopalliance.intercept.MethodInvocation;
 4 import java.util.Arrays;
 5 /**
 6  * Title: 类的主题(开发人员填写)
 7  * Description: 该类的功能
 8  *
 9  * @author jihuan
10  * @create 2017-05-19
11  * @version: 1.0
12  */
13 public class AroundMethod implements MethodInterceptor {
14     @Override
15     public Object invoke(MethodInvocation methodInvocation) throws Throwable {
16         System.out.println("method  name:" + methodInvocation.getMethod().getName());
17         System.out.println("method  arguments" + Arrays.toString(methodInvocation.getArguments()));
18         System.out.println("Around  method : before ");
19         try{
20             Object result = methodInvocation.proceed();
21             System.out.println("Around method : after ");
22             return  result;
23         }catch(IllegalArgumentException e){
24             System.out.println("Around method : throw  an  exception ");
25             throw  e;
26         }
27     }
28 }

创建配置文件

<?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-3.0.xsd">

    <bean id="product" class="com.jk.work.aopone.Product">
        <property name="name" value="p2p p2p p2p" />
        <property name="type" value="one year"/>
        <property name="size" value="30000" />
    </bean>

    <bean id="aroundMethod"  class="com.jk.work.aopone.AroundMethod" />

    <bean id="productProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="product"/>
        <property name="interceptorNames">
            <list>
                <value>aroundMethod</value>
            </list>
        </property>
        <property name="proxyTargetClass" value="true"/> <!-- true 表 cglib,false 为jdkproxy(需要property 引入接口)-->
    </bean>
</beans>

运行结果

---------------------
method  name:printName
method  arguments[]
Around  method : before
Product name p2p p2p p2p
Around method : after
---------------------
method  name:printType
method  arguments[]
Around  method : before
Product type one year
Around method : after
----------------------
method  name:printThrowException
method  arguments[]
Around  method : before
Around method : throw  an  exception 

5. 基于正则表达式的实现

采用RegexpMethodPointcutAdvisor来实现。采用的正则匹配规则,大概有四点,举例说明:

com\.service\..* 和 com\.service\..*Service\..* 和 .*get.* 和 .get.*

第一个表达式匹配的应该是com.service包下的所有方法
第二个表达式匹配的应该是com.service包下所有类名以Service结尾的所有方法
第三个表达式匹配的应该是所有类中含有get的方法
第四个表达式匹配的应该是所有类中以get为前缀的方法

具体如何实现,见下方实例:

创建Garden接口

 1 package com.jk.work.aoptwo;
 2
 3 /**
 4  * Created by jihuan on 17/5/20.
 5  */
 6 public interface Garden {
 7
 8     void fruitPlant();
 9
10     void fruitGrow();
11
12     void fruitHarvest();
13 }

创建Garden实现类

 1 package com.jk.work.aoptwo;
 2 /**
 3  * Title: 类的主题(开发人员填写)
 4  * Description: 该类的功能
 5  *
 6  * @author jihuan
 7  * @create 2017-05-20
 8  * @version: 1.0
 9  */
10 public class AppleGarden implements Garden{
11     @Override
12     public void fruitPlant() {
13         System.out.println("Apple plant...");
14     }
15
16     @Override
17     public void fruitGrow() {
18         System.out.println("Apple grow...");
19     }
20
21     @Override
22     public void fruitHarvest() {
23         System.out.println("Apple harvest...");
24     }
25 }

创建拦截类,采用MethodInterceptor,实现方法前后拦截

 1 package com.jk.work.aoptwo;
 2 import org.aopalliance.intercept.MethodInterceptor;
 3 import org.aopalliance.intercept.MethodInvocation;
 4 /**
 5  * Title: 类的主题(开发人员填写)
 6  * Description: 该类的功能
 7  *
 8  * @author jihuan
 9  * @create 2017-05-20
10  * @version: 1.0
11  */
12 public class GardenAroundAdvice implements MethodInterceptor {
13     @Override
14     public Object invoke(MethodInvocation methodInvocation) throws Throwable {
15         before();
16         Object result=methodInvocation.proceed();
17         after();
18         return result;
19     }
20     private void before(){
21         System.out.println("before......");
22     }
23     private void after(){
24         System.out.println("after......");
25     }
26 } 

创建配置文件,AppleGarden下所有以fruit开头的方法进行切面拦截

<?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-3.0.xsd">  

     <!--果园-->
    <bean id="appleGarden" class="com.jk.work.aoptwo.AppleGarden" />
    <bean id="gardenAroundAdvice" class="com.jk.work.aoptwo.GardenAroundAdvice" />
    <bean id="gardenAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice" ref="gardenAroundAdvice" />
        <property name="pattern" value="com.jk.work.aoptwo.AppleGarden.fruit.*" />
    </bean>

    <bean id="productProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="target" ref="appleGarden"/>
        <property name="interceptorNames">
            <list>
                <value>gardenAdvisor</value>
            </list>
        </property>
        <property name="proxyTargetClass" value="true"/> <!-- true 表 cglib,false 为jdkproxy(需要property 引入接口)-->
    </bean>
</beans>

测试类

package com.jk.work.aoptwo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Title: 类的主题(开发人员填写)
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-20
 * @version: 1.0
 */
public class Test {
    public static void main(String[] args) {
        ApplicationContext context  = new ClassPathXmlApplicationContext("classpath:spring/spring-aop.xml");
        AppleGarden appleGarden  =   (AppleGarden) context.getBean("productProxy");
        System.out.println("----------1-----------");
        appleGarden.fruitPlant();
        System.out.println("----------2----------");
        appleGarden.fruitGrow();
        System.out.println("----------3-----------");
        appleGarden.fruitHarvest();

    }
}

运行效果:

----------1-----------
before......
Apple plant...
after......
----------2----------
before......
Apple grow...
after......
----------3-----------
before......
Apple harvest...
after......

Process finished with exit code 0

6. 基于自动代理的实现

采用自动代理的好处,可以减少配置,简化开发,spring的自动代理,采用了三种方式:

1)Advisor形式,实现类为DefaultAdvisorAutoProxyCreator;

2)Bean形式,实现类为BeanNameAutoProxyCreator;

3)AspjectJ注解形式,实现方式是@Aspect。

具体实例

 Advisor形式,实现类为DefaultAdvisorAutoProxyCreator

创建sprng-aop.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
     <!--果园-->
    <bean id="appleGarden" class="com.jk.work.aoptwo.AppleGarden" />
    <bean id="gardenAroundAdvice" class="com.jk.work.aoptwo.GardenAroundAdvice" />
    <bean id="gardenAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice" ref="gardenAroundAdvice" />
        <property name="pattern" value="com.jk.work.aoptwo.AppleGarden.fruit.*" />
    </bean>
    <!--自动代理-->
    <bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
      <property name="optimize" value="true"/><!-- true 自动寻找代理类,有接口,使用jdkproxy,否则采用cglib-->
    </bean>
</beans>

测试类:

package com.jk.work.aoptwo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Title: 类的主题(开发人员填写)
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-20
 * @version: 1.0
 */
public class Test2 {
    public static void main(String[] args) {
        ApplicationContext context  = new ClassPathXmlApplicationContext("classpath:spring/spring-aop.xml");
        AppleGarden appleGarden  =   (AppleGarden) context.getBean("appleGarden");
        System.out.println("----------1-----------");
        appleGarden.fruitPlant();
        System.out.println("----------2----------");
        appleGarden.fruitGrow();
        System.out.println("----------3-----------");
        appleGarden.fruitHarvest();
    }
}

运行效果

----------1-----------
before......
Apple plant...
after......
----------2----------
before......
Apple grow...
after......
----------3-----------
before......
Apple harvest...
after......

Bean形式,实现类为BeanNameAutoProxyCreator

创建spring-aop.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
     <!--果园-->
    <bean id="appleGarden" class="com.jk.work.aoptwo.AppleGarden" />
    <bean id="gardenAroundAdvice" class="com.jk.work.aoptwo.GardenAroundAdvice" />
    <bean id="gardenAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice" ref="gardenAroundAdvice" />
        <property name="pattern" value="com.jk.work.aoptwo.AppleGarden.fruit.*" />
    </bean>

    <!--自动代理-->
    <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
        <property name="beanNames" value="*Garden" />
        <property name="interceptorNames" value="gardenAdvisor"/>
        <property name="optimize" value="true"/> <!--true 使用jdkproxy,false 采用cglib-->
    </bean>
</beans>

测试类:

package com.jk.work.aoptwo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Title: 类的主题(开发人员填写)
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-20
 * @version: 1.0
 */
public class Test2 {
    public static void main(String[] args) {
        ApplicationContext context  = new ClassPathXmlApplicationContext("classpath:spring/spring-aop.xml");
        AppleGarden appleGarden  =   (AppleGarden) context.getBean("appleGarden");
        System.out.println("----------1-----------");
        appleGarden.fruitPlant();
        System.out.println("----------2----------");
        appleGarden.fruitGrow();
        System.out.println("----------3-----------");
        appleGarden.fruitHarvest();
    }
}

运行效果

----------1-----------
before......
Apple plant...
after......
----------2----------
before......
Apple grow...
after......
----------3-----------
before......
Apple harvest...
after......

AspjectJ注解形式,实现类是AnnotationAwareAspectJAutoProxyCreator,在AspjectJ注解部分说明。

7. AspectJ注解

AspectJ注解方式,采用execution表达式进行切面拦截

创建spring-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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.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="com.*"/>
     <!--果园-->
    <bean id="appleGarden" class="com.jk.work.aoptwo.AppleGarden" />
    <bean id="gardenAroundAdvice" class="com.jk.work.aoptwo.GardenAroundAdvice" />
    <bean id="gardenAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice" ref="gardenAroundAdvice" />
        <property name="pattern" value="com.jk.work.aoptwo.AppleGarden.fruit.*" />
    </bean>
    <!--aspectj-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

创建AroundAspect 拦截类

 1 package com.jk.work.aoptwo;
 2 import org.aspectj.lang.ProceedingJoinPoint;
 3 import org.aspectj.lang.annotation.Around;
 4 import org.aspectj.lang.annotation.Aspect;
 5 import org.springframework.stereotype.Component;
 6
 7 /**
 8  * Title: 类的主题(开发人员填写)
 9  * Description: 该类的功能
10  *
11  * @author jihuan
12  * @create 2017-05-20
13  * @version: 1.0
14  */
15 @Aspect
16 @Component
17 public class AroundAspect {
18     @Around("execution(* com.jk.work.aoptwo.AppleGarden.*(..))")
19     public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
20         handleBefore();
21         Object rs=proceedingJoinPoint.proceed();
22         handleAfter();
23         return  rs;
24     }
25
26     private void handleBefore(){
27         System.out.println("=====before=====");
28     }
29     private void handleAfter(){
30         System.out.println("=====after=====");
31     }
32 }

测试类

package com.jk.work.aoptwo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Title: 类的主题(开发人员填写)
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-20
 * @version: 1.0
 */
public class Test2 {
    public static void main(String[] args) {
        ApplicationContext context  = new ClassPathXmlApplicationContext("classpath:spring/spring-aop.xml");
        AppleGarden appleGarden  =   (AppleGarden) context.getBean("appleGarden");
        System.out.println("----------1-----------");
        appleGarden.fruitPlant();
        System.out.println("----------2----------");
        appleGarden.fruitGrow();
        System.out.println("----------3-----------");
        appleGarden.fruitHarvest();
    }
}

运行效果

----------1-----------
=====before=====
Apple plant...
=====after=====
----------2----------
=====before=====
Apple grow...
=====after=====
----------3-----------
=====before=====
Apple harvest...
=====after=====

AspectJ @DeclareParents 注解,目标是对于一个已有的类引入新的接口,可以使用另一个接口类的功能,属于一种对类的扩展

创建新的接口Worker类

1 package com.jk.work.aoptwo;
2
3 /**
4  * Created by jihuan on 17/5/20.
5  */
6 public interface Worker {
7
8     void work(String task);
9 } 

创建Worker的实现类

package com.jk.work.aoptwo;
/**
 * Title: 类的主题(开发人员填写)
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-20 17:43
 * @version: 1.0
 */
public class AppleWorker implements Worker{
    @Override
    public void work(String task) {
        System.out.println("start work..."+task);
    }
}

创建拦截器AroundAspect2

package com.jk.work.aoptwo;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component;

/**
 * Title: 类的主题(开发人员填写)
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-20 17:40
 * @version: 1.0
 */
@Aspect
@Component
public class AroundAspect2 {
    @DeclareParents(value = "com.jk.work.aoptwo.AppleGarden",defaultImpl =AppleWorker.class )
    private Worker worker;
}

spring-aop.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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.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="com.*"/>
     <!--果园-->
    <bean id="appleGarden" class="com.jk.work.aoptwo.AppleGarden" />
    <bean id="gardenAroundAdvice" class="com.jk.work.aoptwo.GardenAroundAdvice" />
    <bean id="gardenAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
        <property name="advice" ref="gardenAroundAdvice" />
        <property name="pattern" value="com.jk.work.aoptwo.AppleGarden.fruit.*" />
    </bean>
    <!--aspectj-->
    <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

创建测试类

package com.jk.work.aoptwo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * Title: 类的主题(开发人员填写)
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-20 17:48
 * @version: 1.0
 */
public class Test3 {
    public static void main(String[] args) {
        ApplicationContext context  = new ClassPathXmlApplicationContext("classpath:spring/spring-aop.xml");
        AppleGarden appleGarden  =   (AppleGarden) context.getBean("appleGarden");
        Worker worker=(Worker)appleGarden;
        System.out.println("----------1-----------");
        worker.work("plant");
        appleGarden.fruitPlant();
        System.out.println("----------2----------");
        worker.work("watering");
        appleGarden.fruitGrow();
        System.out.println("----------3-----------");
        appleGarden.fruitHarvest();
        worker.work("Harvest");
    }
}

运行效果

----------1-----------
start work...plant
Apple plant...
----------2----------
start work...watering
Apple grow...
----------3-----------
Apple harvest...
start work...Harvest

 

AspjectJ注解自动代理方式的实现

创建拦截类

package com.jk.work.aoptwo;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
/**
 * Title: 类的主题(开发人员填写)
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-20 17:21
 * @version: 1.0
 */
@Aspect
@Component
public class AroundAspect {
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{
        handleBefore();
        Object rs=proceedingJoinPoint.proceed();
        handleAfter();
        return  rs;
    }

    private void handleBefore(){
        System.out.println("=====before=====");
    }
    private void handleAfter(){
        System.out.println("=====after=====");
    }
}

spring-aop.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:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans-3.0.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="com.*"/>

    <!--aspectj-->
    <aop:config>
        <aop:aspect ref="aroundAspect">
            <aop:around method="around" pointcut="execution(* com.jk.work.aoptwo.AppleGarden.*(..))"/>
        </aop:aspect>
    </aop:config>
    <aop:aspectj-autoproxy proxy-target-class="true"/>
</beans>

测试类

package com.jk.work.aoptwo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Title: 类的主题(开发人员填写)
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-20 11:04
 * @version: 1.0
 */
public class Test2 {
    public static void main(String[] args) {
        ApplicationContext context  = new ClassPathXmlApplicationContext("classpath:spring/spring-aop.xml");
        AppleGarden appleGarden  =   (AppleGarden) context.getBean("appleGarden");
        System.out.println("----------1-----------");
        appleGarden.fruitPlant();
        System.out.println("----------2----------");
        appleGarden.fruitGrow();
        System.out.println("----------3-----------");
        appleGarden.fruitHarvest();
    }
}

运行效果

package com.jk.work.aoptwo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
 * Title: 类的主题(开发人员填写)
 * Description: 该类的功能
 *
 * @author jihuan
 * @create 2017-05-20 11:04
 * @version: 1.0
 */
public class Test2 {
    public static void main(String[] args) {
        ApplicationContext context  = new ClassPathXmlApplicationContext("classpath:spring/spring-aop.xml");
        AppleGarden appleGarden  =   (AppleGarden) context.getBean("appleGarden");
        System.out.println("----------1-----------");
        appleGarden.fruitPlant();
        System.out.println("----------2----------");
        appleGarden.fruitGrow();
        System.out.println("----------3-----------");
        appleGarden.fruitHarvest();
    }
}

总结

AOP的用法较多,熟悉每一种用法,能更好的在项目中发挥作用。AOP其实就是一种拦截器,底层采用JDKProxy动态代理和Cglib实现动态代理。对于有接口的形式采用JDKProxy加载处理目标对象。对于没有接口的普通类采用Cglib进行对象的拦截对出。JDKProxy的底层是java反射,Cglib的底层是调asm开源包。

如需转载,请标明本文作者:源码在深山,出处:博客园,原文链接:http://www.cnblogs.com/love-jk/p/spring-api.html

参考:

1) http://blog.csdn.net/topwqp/article/details/8695180

2)   http://www.cnblogs.com/zhaozihan/p/5953063.html

3)《轻量级Java EE企业应用实战》第三版

时间: 2024-10-12 20:14:03

Spring-AOP用法总结的相关文章

Spring AOP用法详解

什么是AOP AOP:Aspect Oriented Programming,中文翻译为"面向切面编程".面向切面编程是一种编程范式,它作为OOP面向对象编程的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理.权限控制.缓存控制.日志打印等等.AOP采取横向抽取机制,取代了传统纵向继承体系的重复性代码 AOP把软件的功能模块分为两个部分:核心关注点和横切关注点.业务处理的主要功能为核心关注点,而非核心.需要拓展的功能为横切关注点.AOP的作用在于分离系统中的各种关注点,

Java Spring AOP用法

Spring AOP Java web 环境搭建 Java web 项目搭建 Java Spring IOC用法 spring提供了两个核心功能,一个是IoC(控制反转),另外一个便是Aop(面向切面编程),IoC有助于应用对象之间的解耦,AOP则可以实现横切关注点(如日志.安全.缓存和事务管理)与他们所影响的对象之间的解耦. 1.简介 AOP主要包含了通知.切点和连接点等术语,介绍如下 通知(Advice) 通知定义了切面是什么以及何时调用,何时调用包含以下几种 Before 在方法被调用之前

Spring AOP切点表达式用法总结

1. 简介 面向对象编程,也称为OOP(即Object Oriented Programming)最大的优点在于能够将业务模块进行封装,从而达到功能复用的目的.通过面向对象编程,不同的模板可以相互组装,从而实现更为复杂的业务模块,其结构形式可用下图表示: 面向对象编程解决了业务模块的封装复用的问题,但是对于某些模块,其本身并不独属于摸个业务模块,而是根据不同的情况,贯穿于某几个或全部的模块之间的.例如登录验证,其只开放几个可以不用登录的接口给用户使用(一般登录使用拦截器实现,但是其切面思想是一致

Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解

原创整理不易,转载请注明出处:Spring AOP注解通过@Autowired,@Resource,@Qualifier,@PostConstruct,@PreDestroy注入属性的配置文件详解 代码下载地址:http://www.zuidaima.com/share/1772661373422592.htm 本文介绍了使用Spring注解注入属性的方法.使用注解以前,注入属性通过类以及配置文件来实现.现在,注入属性可以通过引入@Autowired注解,或者@Resource,@Qualifi

Spring AOP之切入点指示符

execution是Spring AOP中最主要的切入点指示符,该切入点的用法相对复杂,execution表达式的格式如下: execution(modifiers-pattern? ret-type=pattern declaring-type-pattern?name-pattern(param-pattern) throws-pattern?) 上面格式中的execution是不变的,用于作为execution表达式的开头,整个表达式中的解释如下: modifiers-pattern:指定

正确理解Spring AOP中的Around advice

Spring AOP中,有Before advice和After advice,这两个advice从字面上就可以很容易理解,但是Around advice就有点麻烦了. 乍一看好像是Before advice和After advice的组合,也就是说pointcut会在joinpoint执行前后各执行一次.但是这种理解是不正确的,如果这样理解的话,就会产生这样的疑问:spring aop Around类型为什么只执行一次 ,这个帖子是我碰巧看到. 那么怎么样理解才是正确的呢?我们来看一下Spri

Spring技术内幕:Spring AOP的实现原理(二)

**二.AOP的设计与实现 1.JVM的动态代理特性** 在Spring AOP实现中, 使用的核心技术时动态代理,而这种动态代理实际上是JDK的一个特性.通过JDK的动态代理特性,可以为任意Java对象创建代理对象,对于具体使用来说,这个特性使通过Java Reflection API来完成的.在此之前先简要复习一下Proxy模式,其静态类图如下: 我们可以看到有一个RealSubject,这个对象是目标对象,而在代理模式的设计中,会设计一个接口和目标对象一致的代理对象Proxy,它们都实现了

Spring AOP中的动态代理

0  前言 1  动态代理 1.1 JDK动态代理 1.2 CGLIB动态代理 1.2.1 CGLIB的代理用法 1.2.2 CGLIB的过滤功能 2  Spring AOP中的动态代理机制 2.1 JdkDynamicAopProxy 2.2 CglibAopProxy 3 总结 0  前言 前一个季度旅游TDC的Thames服务有几次宕机,根据组内原因认真查找发现是数据库事务造成的,后来把服务中的事务配置全部去掉,服务恢复正常.根据这次教训,虽然现在还是很难确定是哪一个方面的真正原因,但是激

基于@AspectJ配置Spring AOP之一--转

原文地址:http://tech.it168.com/j/2007-08-30/200708302209432.shtml 概述 在低版本Spring中定义一个切面是比较麻烦的,需要实现特定的接口,并进行一些较为复杂的配置,低版本Spring AOP的配置是被批评最多的地方.Spring听取这方面的批评声音,并下决心彻底改变这一现状.在Spring2.0中,Spring AOP已经焕然一新,你可以使用@AspectJ注解非常容易的定义一个切面,不需要实现任何的接口. Spring2.0采用@As

Spring AOP 切面编程的方法

spring aop的使用分为两种,一种是使用注解来实现,一种是使用配置文件来实现. 先来简单的介绍一下这两种方法的实现,接下来详细的介绍各处的知识点便于查阅.目录如下: 1.基于注解实现spring aop 2.基于配置文件实现spring aop 3.增强的分类 4.切点表达式的构成 1.基于注解来实现的方法 基于注解并不意味着不需要配置文件,只不过是在配置文件中所需要的配置很少.切面编程,显然我们需要一个增强类,一个被增强的普通类. 配置文件中需要添加以下的内容 xmlns:aop="ht