前言
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企业应用实战》第三版