Spring AOP的两种实现方式
2015-08-27 22:26
746 查看
AOP常用实现方式是一个采用声明的方式来实现,一个采用注解的方式来实现。
温习下一些概念
Joinpoint(连接点):程序执行时的某个特定的点,在Spring中就是某一个方法的执行 。
Pointcut(切点):说的通俗点,spring中AOP的切点就是指一些方法的集合,而这些方法
是需要被增强、被代理的。一般都是按照一定的约定规则来表示的,如正则表达式等。切点是
由一类连接点组成。
Advice(通知):还是说的通俗点,就是在指定切点上要干些什么。
Advisor(通知器):其实就是切点和通知的结合 。
方式一:采用声明的方式实现(在XML文件中配置),大致步骤为:配置文件中配置pointcut, 在java中用编写实际的aspect 类, 针对对切入点进行相关的业务处理。
业务接口:
业务实现:
切面类:
Spring配置:
测试类:
测试结果:
doBefore:现在时间是.........
doAround开始:现在时间是.........
lixiaoxi已经签到了!
doAfter:现在时间是.........
返回值result===================lixiaoxi
输出:signIn;com.aop.service.impl.BaseBusinessImpl@1d95492;lixiaoxi
doAround结束:现在时间是.........
方式二: 采用注解来做aop, 主要是将写在spring 配置文件中的连接点写到注解里面。
首先,在spring配置文件中加入如下配置(用来申明spring对@AspectJ的支持): <aop:aspectj-autoproxy/>
如果你使用的是DTD,可以在Spring配置文件中加入如下配置来申明spring对@Aspect的支
持: <bean class="org.springframework.aop.aspectj.annotation.
AnnotationAwareAspectJAutoProxyCreator" />
目标对象类与上边一样
具体通知类如下:
Spring的配置:
测试类:
测试结果与上相同。
注意:
1.环绕方法通知,环绕方法通知要注意必须给出调用之后的返回值,否则被代理的方法会停止调用并返回null,除非你真的打算这么做。
2.只有环绕通知才可以使用JoinPoint的子类ProceedingJoinPoint,各连接点类型可以调用代理的方法,并获取、改变返回值。
补充:
1.<aop:pointcut>如果位于<aop:aspect>元素中,则命名切点只能被当前<aop:aspect>内定义的元素访问到,为了能被整个<aop:config>元素中定义的所有增强访问,则必须在<aop:config>下定义切点。
2.如果在<aop:config>元素下直接定义<aop:pointcut>,必须保证<aop:pointcut>在<aop:aspect>之前定义。<aop:config>下还可以定义<aop:advisor>,三者在<aop:config>中的配置有先后顺序的要求:首先必须是<aop:pointcut>,然后是<aop:advisor>,最后是<aop:aspect>。而在<aop:aspect>中定义的<aop:pointcut>则没有先后顺序的要求,可以在任何位置定义。
• <aop:pointcut>:用来定义切入点,该切入点可以重用;
• <aop:advisor>:用来定义只有一个通知和一个切入点的切面;
• <aop:aspect>:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;和advisor的区别就在此,advisor只包含一个通知和一个切入点。
3.在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点"
例如定义切入点表达式
execution(* com.sample.service.impl..*.*(..))
execution()是最常用的切点函数,其语法如下所示:
整个表达式可以分为五个部分:
1、execution(): 表达式主体。
2、第一个*号:表示返回类型,*号表示所有的类型。
3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
4、第二个*号:表示类名,*号表示所有的类。
5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
温习下一些概念
Joinpoint(连接点):程序执行时的某个特定的点,在Spring中就是某一个方法的执行 。
Pointcut(切点):说的通俗点,spring中AOP的切点就是指一些方法的集合,而这些方法
是需要被增强、被代理的。一般都是按照一定的约定规则来表示的,如正则表达式等。切点是
由一类连接点组成。
Advice(通知):还是说的通俗点,就是在指定切点上要干些什么。
Advisor(通知器):其实就是切点和通知的结合 。
方式一:采用声明的方式实现(在XML文件中配置),大致步骤为:配置文件中配置pointcut, 在java中用编写实际的aspect 类, 针对对切入点进行相关的业务处理。
业务接口:
package com.aop.service; public interface IBaseBusiness { public String signIn(); }
业务实现:
package com.aop.service.impl; import com.aop.service.IBaseBusiness; public class BaseBusinessImpl implements IBaseBusiness{ private String name; public void setName(String name){ this.name=name; } public String getName(){ return this.name; } public String signIn(){ System.out.println(name+"已经签到了!"); return name; } }
切面类:
package com.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; /** * 定义一个切面 * @author lixiaoxi * */ public class AspectAdvice { /** * 前置通知 */ public void doBefore(JoinPoint jp){ //System.out.println("===========进入before advice============ \n"); //System.out.print("准备在" + jp.getTarget().getClass() + "对象上用"); //System.out.print(jp.getSignature().getName() + "方法进行签到\n\n"); System.out.println("doBefore:现在时间是........."); } /** * 后置通知 */ public void doAfter(JoinPoint jp,String result){ //System.out.println("==========进入after advice=========== \n"); //System.out.println("切入点方法执行完了 \n"); // //System.out.print("在" + jp.getTarget().getClass() + "对象上用"); //System.out.print(jp.getSignature().getName() + "方法进行了签到\n\n"); System.out.println("doAfter:现在时间是........."); System.out.println("返回值result==================="+result); } /** * 环绕通知 */ public void doAround(ProceedingJoinPoint pjp) throws Throwable{ //System.out.println("===========进入around环绕方法!=========== \n"); System.out.println("doAround开始:现在时间是........."); //System.out.println("调用方法之前: 执行!\n"); // 调用方法的参数 Object[] args = pjp.getArgs(); // 调用的方法名 String method = pjp.getSignature().getName(); // 获取目标对象 Object target = pjp.getTarget(); // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行 Object result = pjp.proceed(); System.out.println("输出:" + method + ";" + target + ";" + result); //System.out.println("调用方法结束:之后执行!\n"); System.out.println("doAround结束:现在时间是........."); //return obj; } /** * 异常通知 * * @param jp * @param e */ public void doThrow(JoinPoint jp, Throwable e) { System.out.println("doThrow:现在时间是.........."); } }
Spring配置:
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <!-- 声明一个业务类 --> <bean id="baseBusiness" class="com.aop.service.impl.BaseBusinessImpl"> <property name="name" value="lixiaoxi"></property> </bean> <!-- 声明通知类 --> <bean id="aspectAdvice" class="com.aop.AspectAdvice" /> <aop:config> <aop:aspect ref="aspectAdvice"> <aop:pointcut id="pointcut" expression="execution(* com.aop.service.impl.BaseBusinessImpl.sign*(..))"/> <aop:before method="doBefore" pointcut-ref="pointcut"/> <aop:after-returning method="doAfter" pointcut-ref="pointcut" returning="result"/> <aop:around method="doAround" pointcut-ref="pointcut"/> <aop:after-throwing method="doThrow" pointcut-ref="pointcut" throwing="e"/> </aop:aspect> </aop:config> </beans>
测试类:
package com.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.aop.service.IBaseBusiness; public class Test { public static void main(String[] args) throws Exception{ ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext.xml"); IBaseBusiness e = (IBaseBusiness)act.getBean("baseBusiness"); e.signIn(); } }
测试结果:
doBefore:现在时间是.........
doAround开始:现在时间是.........
lixiaoxi已经签到了!
doAfter:现在时间是.........
返回值result===================lixiaoxi
输出:signIn;com.aop.service.impl.BaseBusinessImpl@1d95492;lixiaoxi
doAround结束:现在时间是.........
方式二: 采用注解来做aop, 主要是将写在spring 配置文件中的连接点写到注解里面。
首先,在spring配置文件中加入如下配置(用来申明spring对@AspectJ的支持): <aop:aspectj-autoproxy/>
如果你使用的是DTD,可以在Spring配置文件中加入如下配置来申明spring对@Aspect的支
持: <bean class="org.springframework.aop.aspectj.annotation.
AnnotationAwareAspectJAutoProxyCreator" />
目标对象类与上边一样
具体通知类如下:
package com.aop; import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.AfterReturning; /** * 使用@Aspect 注解的类, Spring 将会把它当作一个特殊的Bean(一个切面),也就是 * 不对这个类本身进行动态代理 */ @Aspect public class AspectJAdvice { /** * 必须为final String类型的,注解里要使用的变量只能是静态常量类型的 */ public static final String EDP="execution(* com.aop.service.impl.BaseBusinessImpl.sign*(..))"; /** * 切面的前置方法 即方法执行前拦截到的方法 * 在目标方法执行之前的通知 */ @Before(EDP) public void doBefore(JoinPoint jp){ System.out.println("doBefore c04f :现在时间是........."); } /** * 在方法正常执行通过之后执行的通知叫做返回通知 * 可以返回到方法的返回值 在注解后加入returning */ @AfterReturning(value=EDP,returning="result") public void doAfter(JoinPoint jp,String result){ System.out.println("doAfter:现在时间是........."); System.out.println("返回值result==================="+result); } /** * 环绕通知 */ @Around(EDP) public void doAround(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("doAround开始:现在时间是........."); //System.out.println("调用方法之前: 执行!\n"); // 调用方法的参数 Object[] args = pjp.getArgs(); // 调用的方法名 String method = pjp.getSignature().getName(); // 获取目标对象 Object target = pjp.getTarget(); // 执行完方法的返回值:调用proceed()方法,就会触发切入点方法执行 Object result = pjp.proceed(); System.out.println("输出:" + method + ";" + target + ";" + result); //System.out.println("调用方法结束:之后执行!\n"); System.out.println("doAround结束:现在时间是........."); } /** * 在目标方法非正常执行完成 发生异常 抛出异常的时候会走此方法 * 获得异常可以用throwing * @param joinPoint * @param e */ @AfterThrowing(value=EDP,throwing="e") public void doThrow(JoinPoint jp, Exception e) { System.out.println("doThrow:现在时间是.........."); } }
Spring的配置:
<?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:p="http://www.springframework.org/schema/p" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <aop:aspectj-autoproxy/> <!-- 声明一个业务类 --> <bean id="baseBusiness" class="com.aop.service.impl.BaseBusinessImpl"> <property name="name" value="lixiaoxi"></property> </bean> <!-- 声明通知类 --> <bean id="aspectJAdvice" class="com.aop.AspectJAdvice" /> </beans>
测试类:
package com.aop; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; import com.aop.service.IBaseBusiness; public class Test1 { public static void main(String[] args) throws Exception{ ApplicationContext act = new ClassPathXmlApplicationContext("applicationContext1.xml"); IBaseBusiness e = (IBaseBusiness)act.getBean("baseBusiness"); e.signIn(); } }
测试结果与上相同。
注意:
1.环绕方法通知,环绕方法通知要注意必须给出调用之后的返回值,否则被代理的方法会停止调用并返回null,除非你真的打算这么做。
2.只有环绕通知才可以使用JoinPoint的子类ProceedingJoinPoint,各连接点类型可以调用代理的方法,并获取、改变返回值。
补充:
1.<aop:pointcut>如果位于<aop:aspect>元素中,则命名切点只能被当前<aop:aspect>内定义的元素访问到,为了能被整个<aop:config>元素中定义的所有增强访问,则必须在<aop:config>下定义切点。
2.如果在<aop:config>元素下直接定义<aop:pointcut>,必须保证<aop:pointcut>在<aop:aspect>之前定义。<aop:config>下还可以定义<aop:advisor>,三者在<aop:config>中的配置有先后顺序的要求:首先必须是<aop:pointcut>,然后是<aop:advisor>,最后是<aop:aspect>。而在<aop:aspect>中定义的<aop:pointcut>则没有先后顺序的要求,可以在任何位置定义。
• <aop:pointcut>:用来定义切入点,该切入点可以重用;
• <aop:advisor>:用来定义只有一个通知和一个切入点的切面;
• <aop:aspect>:用来定义切面,该切面可以包含多个切入点和通知,而且标签内部的通知和切入点定义是无序的;和advisor的区别就在此,advisor只包含一个通知和一个切入点。
3.在使用spring框架配置AOP的时候,不管是通过XML配置文件还是注解的方式都需要定义pointcut"切入点"
例如定义切入点表达式
execution(* com.sample.service.impl..*.*(..))
execution()是最常用的切点函数,其语法如下所示:
整个表达式可以分为五个部分:
1、execution(): 表达式主体。
2、第一个*号:表示返回类型,*号表示所有的类型。
3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。
4、第二个*号:表示类名,*号表示所有的类。
5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。
相关文章推荐
- java 集合
- Introduction to Java Programming编程题9.13<回文字符串(在命令行传字符串)>
- java环境变量配置
- Introduction to Java Programming编程题9.12<变位词>
- Struts2中的ModelDriven机制及其运用(转)
- 加载
- [leetcode-198]House Robber(java)
- Java多线程中join方法的理解
- 解决Struts2开发模式异常问题
- java中outer的使用
- restful springmvc 参数验证和异常处理
- 《Java从入门到精通》src9-25
- 《Java从入门到精通》src9-25
- netbeans修改辅助红线
- JavaFX中javafx.concurrent.Task类的使用
- java.lang.IllegalStateException: BeanFactory
- Spring之IOC容器注入
- 续上一篇,注册、登录Java程序(集合存储数据)
- 什么是Java的永久代(PermGen)内存泄漏
- Java——Java基础知识