spring aop advice
1.前置通知(BeforeAdvice):
import java.lang.reflect.Method; import org.springframework.aop.MethodBeforeAdvice; public class HelloBeforeAdvice implements MethodBeforeAdvice{ public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("do something before some method");
}
}
如果出现 The hierarchy of the type HelloBeforeAdvice is inconsistent错误 , 是缺少相关的jar或者jdk环境不对。
2.后置通知(AfterAdvice)
import java.lang.reflect.Method; import org.springframework.aop.AfterReturningAdvice; public class HelloAfterAdvice implements AfterReturningAdvice { public void afterReturning(Object result, Method method, Object[] args, Object target) throws Throwable {
System.out.println("do something after the method");
} }
3. Test client
import org.springframework.aop.framework.ProxyFactory; public class TestClient { public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory();//创建代理工厂
proxyFactory.setTarget(new HelloImpl());
proxyFactory.addAdvice(new HelloBeforeAdvice());
proxyFactory.addAdvice(new HelloAfterAdvice());
Hello helloProxy = (Hello) proxyFactory.getProxy();
System.out.println(helloProxy.sayHello("zhangsan"));
}
} ----------------------------
public class HelloImpl implements Hello { public String sayHello(String str) {
System.out.println("hello>>>"+str);
return "hello>>>"+str;
}
}
4. 环绕通知(AroundAdvice)
//aop联盟提供的接口
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; public class HelloAroundAdvice implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before method>>>");
Object result = invocation.proceed();
System.out.println("after method>>");
return result;
}
}
5. spring 配置文件方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:cache="http://www.springframework.org/schema/cache"
xsi:schemaLocation="
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/jdbc
http://www.springframework.org/schema/jdbc/spring-jdbc.xsd
http://www.springframework.org/schema/cache
http://www.springframework.org/schema/cache/spring-cache.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd">
<!-- 自动扫描ppms包 ,将带有注解的类 纳入spring容器管理 -->
<context:component-scan base-package="com.cdv.ppms"></context:component-scan> <bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.cdv.ppms.Hello"/><!-- 需要代理的接口 -->
<property name="target" ref="helloImpl"/><!-- 接口实现类 , 此处需要是ref 否则object is not an instance of declaring class-->
<property name="interceptorNames"><!-- 拦截器 名称-->
<list>
<value>helloAroundAdvice</value>
</list>
</property>
</bean>
<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>
</beans>
import org.springframework.stereotype.Component; @Component
public class HelloImpl implements Hello {
//...
} @Component
public class HelloAroundAdvice implements MethodInterceptor {
//....
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestXMLClient { public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Hello hello = (Hello) context.getBean("helloProxy");
hello.sayHello("test xml");
}
}
6. 抛出通知(ThrowAdvice)
import java.lang.reflect.Method;
import org.springframework.aop.ThrowsAdvice;
import org.springframework.stereotype.Component; @Component
public class HelloThrowAdvice implements ThrowsAdvice{
public void afterThrowing(Method method, Object[] args, Object target, Exception e){
System.out.println("-------------------Throw Exception------------------------");
System.out.println("target class>>"+target.getClass().getName());
System.out.println("method class>>" + method.getName());
System.out.println("exception message>>"+e.getMessage());
System.out.println("-------------------Throw Exception------------------------");
}
}
<bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.cdv.ppms.Hello"/><!-- 需要代理的接口 -->
<property name="target" ref="helloImpl"/><!-- 接口实现类 -->
<property name="interceptorNames"><!-- 拦截器 名称-->
<list>
<value>helloAroundAdvice</value>
<value>testThrowAdvice</value>
</list>
</property>
</bean>
import org.springframework.stereotype.Component; @Component
public class HelloImpl implements Hello { public String sayHello(String str) {
System.out.println("hello>>>"+str);
throw new RuntimeException("error>>");//加入异常以便测试
}
}
7. 引入通知(Introduction Advice)
对方法的增强叫织入(Weaving),对类的增强叫引入(Introduction)
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;
import org.springframework.stereotype.Component;
@Component
public class HelloIntroAdvice extends DelegatingIntroductionInterceptor implements Apology { /**
*
*/
private static final long serialVersionUID = -3328637206414010549L; public Object invoke(MethodInvocation invocation) throws Throwable{ return super.invoke(invocation);
} public void saySorry(String str) {
System.out.println("introduction advice>>>"+str);
}
}
<bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="interfaces" value="com.cdv.ppms.Apology"/><!-- 需要代理的接口 -->
<property name="target" ref="helloImpl"/><!-- 接口实现类 -->
<property name="interceptorNames"><!-- 拦截器 名称-->
<list>
<value>helloAroundAdvice</value>
<value>helloThrowAdvice</value>
<value>helloIntroAdvice</value>
</list>
</property>
<property name="proxyTargetClass" value="true"></property><!--代理目标类, 默认false代理接口-->
</bean>
<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestXMLClient { public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloImpl helloImpl = (HelloImpl) context.getBean("helloProxy");
helloImpl.sayHello("test xml");
Apology apology = (Apology) helloImpl;//将目标类向上强制转型为Apology接口, 这时引入通知给我们带来的特性, 也就是“接口动态实现”功能
apology.saySorry("zhangsan");
}
}
8. 切面(Advisor)
切面(Advisor)封装了通知(Advice)和切点(Pointcut)
import org.springframework.stereotype.Component; @Component
public class HelloImpl implements Hello { public String sayHello(String str) {
System.out.println("hello>>>"+str);
return str;
} public void advisorOne(String name){
System.out.println("advisor one>>>"+name);
} public void advisorTwo(String name){
System.out.println("advisor two>>"+name);
}
}
在代理类中新增以advisor开头的方法,对其进行拦截
<context:component-scan base-package="com.cdv.ppms"></context:component-scan>
<!--定义切面-->
<bean id="helloAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="helloAroundAdvice"/>
<property name="pattern" value="com.cdv.ppms.HelloImpl.advisor.*"></property><!-- 切点 (正则表达式) -->
</bean>
<bean id="helloProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="helloImpl"/><!-- 接口实现类 -->
<property name="interceptorNames" value="helloAdvisor"/>
<property name="proxyTargetClass" value="true"></property>
</bean>
<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>
<bean id="helloAroundAdvice" class="com.cdv.ppms.HelloAroundAdvice"></bean>
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.stereotype.Component;
@Component
public class HelloAroundAdvice implements MethodInterceptor { public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before method>>>");
Object result = invocation.proceed();
System.out.println("after method>>");
return result;
}
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestXMLClient { public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloImpl helloImpl = (HelloImpl) context.getBean("helloProxy");
helloImpl.advisorOne("11111111");
helloImpl.advisorTwo("2222222222"); }
}
-------------around包了两层, 有问题-------------------------------------------
before method>>>
before method>>>
advisor one>>>11111111
after method>>
after method>>
before method>>>
before method>>>
advisor two>>2222222222
after method>>
after method>>
------------------------
随着项目的扩大, 上述的代理配置会越来越多。
9. 自动代理(扫描bean名称)
定义BeanNameAutoProxyCreator,该bean是个bean后处理器,无需被引用,因此没有id属性
<context:component-scan base-package="com.cdv.ppms"></context:component-scan> <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
<property name="beanNames" value="*Impl"/><!--对以Impl结尾的类进行处理-->
<property name="interceptorNames" value="helloAroundAdvice"/>
<property name="optimize" value="true"/>
</bean> <bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>
<bean id="helloAroundAdvice" class="com.cdv.ppms.HelloAroundAdvice"></bean>
测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestXMLClient { public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloImpl helloImpl = (HelloImpl) context.getBean("helloImpl");
helloImpl.advisorOne("11111111");//
helloImpl.advisorTwo("2222222222");
helloImpl.sayHello("zhangwuji");
}
}
10. 自动代理(扫描切面配置)
代理将由DefaultAdvisorAutoProxyCreator自动生成,这个类可以扫描所有的切面类
<context:component-scan base-package="com.cdv.ppms"></context:component-scan>
<bean id="helloAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice" ref="helloAroundAdvice"/>
<property name="pattern" value="com.cdv.ppms.HelloImpl.advisor.*"/>
</bean>
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
<property name="optimize" value="true"/>
</bean>
<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>
<bean id="helloAroundAdvice" class="com.cdv.ppms.HelloAroundAdvice"></bean>
测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestXMLClient { public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloImpl helloImpl = (HelloImpl) context.getBean("helloImpl");
helloImpl.advisorOne("11111111");
helloImpl.advisorTwo("2222222222");
helloImpl.sayHello("zhangwuji");
}
}
//只有符合advisor开头的方法才会被代理
这样在spring的配置中会存在大量的切面配置(想拦截指定注解的方法,就必须拓展DefaultPointcutAdvisor类,自定义一个切面类)。
11. Spring & AspectJ
11-1 基于注解 :通过execution()表达式 拦截方法
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component; @Aspect
@Component
public class HelloAspect { @Around("execution(* com.cdv.ppms.HelloImpl.*(..))")//切点表达式
public Object around(ProceedingJoinPoint pjp) throws Throwable{
before();
Object result = pjp.proceed();
after();
return result;
} private void after() {
System.out.println("hey,, after."); } private void before() {
System.out.println("hey,, before");
}
}
切点表达式
execution()表示拦截的方法, 挂号中定义拦截的规则
上面第一个*表示返回任意类型
第二个*表示HelloImpl类中的任意方法
..表示任意类型参数
<context:component-scan base-package="com.cdv.ppms"></context:component-scan>
<aop:aspectj-autoproxy proxy-target-class="true"/><!-- 默认值为false只能代理接口,当为true时才能代理目标类 -->
<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>
test
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestXMLClient { public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloImpl helloImpl = (HelloImpl) context.getBean("helloImpl");
helloImpl.advisorOne("11111111");
helloImpl.advisorTwo("2222222222");
helloImpl.sayHello("zhangwuji");
}
}
11-2 基于注解 通过AspectJ @annotation表达式拦截方法
自定义注解
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; @Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTag { }
更改aspect类的切点表达式
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component; @Aspect
@Component
public class HelloAspect { @Around("@annotation(com.cdv.ppms.MyTag)")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
before();
Object result = pjp.proceed();
after();
return result;
} private void after() {
System.out.println("hey,, after."); } private void before() {
System.out.println("hey,, before");
}
}
该注解可以标注在方法上,运行时生效
import org.springframework.stereotype.Component; @Component
public class HelloImpl implements Hello { public String sayHello(String str) {
System.out.println("hello>>>"+str);
return str;
}
@MyTag
public void advisorOne(String name){
System.out.println("advisor one>>>"+name);
}
public void advisorTwo(String name){
System.out.println("advisor two>>"+name);
}
}
配置
<context:component-scan base-package="com.cdv.ppms"></context:component-scan>
<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>
测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestXMLClient { public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloImpl helloImpl = (HelloImpl) context.getBean("helloImpl");
helloImpl.advisorOne("11111111");
helloImpl.advisorTwo("2222222222");
helloImpl.sayHello("zhangwuji");
}
}
其他几个注解
@Before @After @AfterThrowing @DeclareParents引入通知 AfterReturning(返回后通知,在方法结束后执行)
11-3 引入通知
Aspect类
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareParents;
import org.springframework.stereotype.Component; @Aspect
@Component
public class HelloAspect {
//something need to do
@DeclareParents(value="com.cdv.ppms.HelloImpl",defaultImpl=com.cdv.ppms.ApologyImpl.class)
private Apology apology; }
接口实现类
public class ApologyImpl implements Apology { public void saySorry(String str) {
System.out.println("apologyImpl>>>"+str);
}
}
配置
<context:component-scan base-package="com.cdv.ppms"></context:component-scan>
<bean id="helloImpl" class="com.cdv.ppms.HelloImpl"></bean>
测试
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestXMLClient { public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
HelloImpl helloImpl = (HelloImpl) context.getBean("helloImpl");
helloImpl.sayHello("zhangwuji");
Apology apology = (Apology) helloImpl;
apology.saySorry("hahahahah");
}
}
spring aop advice的更多相关文章
- spring AOP advice 类型 和 通用的切点的配置方式
spring aop advice的类型: 1.前置通知(before advice) 2.返回后通知(after returning advice) 3.抛出异常后通知(after throwing ...
- Spring AOP Example – Advice
Spring AOP + AspectJ Using AspectJ is more flexible and powerful. Spring AOP (Aspect-oriented progra ...
- Spring AOP Example – Pointcut , Advisor
In last Spring AOP advice examples, the entire methods of a class are intercepted automatically. But ...
- 框架源码系列三:手写Spring AOP(AOP分析、AOP概念学习、切面实现、织入实现)
一.AOP分析 问题1:AOP是什么? Aspect Oriented Programming 面向切面编程,在不改变类的代码的情况下,对类方法进行功能增强. 问题2:我们需要做什么? 在我们的框架中 ...
- Spring -- aop(面向切面编程),前置&后置&环绕&抛异常通知,引入通知,自动代理
1.概要 aop:面向方面编程.不改变源代码,还为类增加新的功能.(代理) 切面:实现的交叉功能. 通知:切面的实际实现(通知要做什么,怎么做). 连接点:应用程序执行过程期间,可以插入切面的地点. ...
- Spring Aop(十四)——Aop自动创建代理对象的原理
转发地址:https://www.iteye.com/blog/elim-2398725 Aop自动创建代理对象的原理 我们在使用Spring Aop时,通常Spring会自动为我们创建目标bean的 ...
- Spring Aop(十)——编程式的Pointcut
转发地址:https://www.iteye.com/blog/elim-2396526 编程式的Pointcut 除了可以通过注解和Xml配置定义Pointcut之外,其实我们还可以通过程序来定义P ...
- Spring Aop(九)——基于正则表达式的Pointcut
转发地址:https://www.iteye.com/blog/elim-2396525 基于正则表达式的Pointcut JdkRegexpMethodPointcut Spring官方为我们提供了 ...
- Spring Aop(八)——advisor标签
转发地址:https://www.iteye.com/blog/elim-2396274 8 advisor标签 advisor标签是需要定义在aspect标签里面的,其作用与aspect类似,可以简 ...
随机推荐
- Windows下启动各服务命令
1. gpedit.msc-----组策略 2. nslookup-------IP地址侦测器 3. explorer-------打开资源管理器 4. logoff---------注销命令 5. ...
- 如何使用新浪微博账户进行应用登录验证(基于Windows Azure Mobile Service 集成登录验证)
使用三方账号登录应用应该对大家来说已经不是什么新鲜事儿了,但是今天为什么还要在这里跟大家聊这个话题呢,原因很简单 Windows Azure Mobiles Service Authenticatio ...
- Android showing LoadingView or EmptyView for Activity or Fragment
这几天利用一些时间,整理了一下,写了一个简单的工具类,用来快速的显示LoadingView或者EmptyView,以前都是定义一个layout,根布局为FrameLayout,再在layout布局文件 ...
- Android 使用NDK编译sipdroid Library
sipdroid是一款开源的运行于Android平台上的voip,目前支持音频和视频通话: 项目拖管地址:http://code.google.com/p/sipdroid/ 下载源代码,导入ecli ...
- Android working with Volley
Volley是google官方推出的一个开源网络访问库,在项目中直接使用它,而不需要写一大堆的重复的代码; 项目主页: https://android.googlesource.com/platfor ...
- HP P1008打印机如何打印特殊纸张
一.问题的提出 HP P1008中间有一个进纸槽,这是干什么的? 二.问题的分析 查说明,说这个进纸槽是叫做优先进纸槽,用于各种非常规的纸张的打印. 三.问题的解决 弄一张特殊尺寸的纸张,打开要编辑的 ...
- (转)在低版本的SDK里使用高版本函数@SuppressLint("NewApi") or @TargetApi?
@SuppressLint 和 @TargetApi达到的效果是一样的,相对于SuppressLint ,TargetApi会根据函数里使用的API,严格匹配SDK版本,给出编译错误,但是Suppre ...
- 实现TabView(页签)效果
今天花了点时间,设计了一个网页上用的tabview(页签.tabcontrol)效果.个人觉得实现得比较不错,网页元素用得比较少,js代码也比较精练.测试了一下支持IE.FireFox以及chrome ...
- DDD:如何表达聚合之间的关系?
大家都能达成的两个共识是: 概念模型中,聚合之间充满着关系(双向). 对象模型中,根据有用性.性能和成本等因素考虑,保留某些必须的关系. 备注:读写分离有利于更好的表达关系,因为某些关系在读取的时候需 ...
- 数据可视化(2)--Justgage
JustGage 是一个 JavaScript 插件来生成很漂亮的仪表盘,基于 Raphaël 库做向量图绘制. JustGage 完全基于 SVG,因此支持几乎所有浏览器,包括:IE6+, Chro ...