Spring框架——AOP代理
来源:互联网 发布:enjoy it 编辑:程序博客网 时间:2024/05/22 03:16
我们知道AOP代理指的就是设计模式中的代理模式。一种是静态代理,高效,但是代码量偏大;另一种就是动态代理,动态代理又分为SDK下的动态代理,还有CGLIB的动态代理。Spring AOP说是实现了AOP联盟定制的标准化接口,也就是说人家的AOP做得很规范,很国际化。我也看了别人写的,Spring框架下的AOP内容确实很多,不过我争取长话短说,把文章篇幅控制好,并且条理清楚一些。
注:本文只关注AOP的切入点,不会涉及任何实战内容,关于实战的内容可以看我的其它文章,O(∩_∩)O~
AOP核心概念
虽然我们自己写AOP会轻松很多,但是Spring框架下,对AOP做了非常细致的划分,因此对概念要有一定的了解。
1、横切关注点
对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
2、切面(aspect)
就如图所示,程序流程会按顺序执行,而切面就像一个平面,在这个流程中间插入。
3、连接点(joinpoint)
被拦截到的点,它可以是程序执行过程中的任意一点,而AOP主要做的是方法上的拦截。
4、切入点(pointcut)
对连接点进行拦截的定义,切面与流程的交点。
5、通知(advice)
所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。
6、目标对象
代理的目标对象
7、织入(weave)
将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction)
在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
AOP的增强分类
在上一篇文章,接触到了增强这个词,增强指的就是代理,指的是在程序流程中,嵌入一些新的内容。通常认为Spring支持5种类型增强,不过我觉得得重新定义一下比较好,我认为应当是3种增强,2种拦截。
前置增强:org.springframework.aop.BeforeAdvice代表前置增强,不过BeforeAdvice是一个空接口,MethodBeforeAdvice是目前可用的前置增强,表示在目标方法执行前实施增强。
后置增强:org.springframework.aop.AfterReturningAdvice代表后增强,表示在目标方法执行后实施增强。
异常抛出增强:org.springframework.aop.ThrowsAdvice代表抛出异常增强,表示在目标方法抛出异常后实施增强。
环绕增强(方法拦截):org.aopalliance.intercept.MethodInterceptor代表环绕增强,对于这个增强,我有自己的看法,从直译上看,它应该叫方法拦截,也就是说实现这个接口,可以不让我们的方法执行。
引介增强:org.springframework.aop.IntroductionInterceptor代表引介增强,IntroductionInterceptor的方法只有一个Class参数,不好使用,实际使用可以直接继承DelegatingIntroductionInterceptor类。它也是一种拦截方法,可以使用表示在目标类中添加一些新的方法和属性。
源码
环绕增强(拦截器)
这个和传统的JDK代理和CGLIB代理最类似,这里你可以获取到你需要调用的方法,你要是想放弃使用前置增强和后置增强,将它们的代码全部放在这里执行,这也是可以的。
具体的使用呢,就比如说:你要做一件很耗内存的操作,执行那个操作之前,你要判断内存容量,要是内存不足了,就放弃对方法的使用,这样的代码逻辑就可以放到这里。
/** * 这是一个拦截器,在某些情况下,选择放弃对方法的使用,其实在这里编写前置代理和后置代理也可以,但是Spring既然提供了其他接口,参照接口实现更加规范 * @author ChenSS * @2017年1月1日 */public class MyMethodInterceptor implements MethodInterceptor{ @Override public Object invoke(MethodInvocation dao) throws Throwable { System.out.println("MyMethodInterceptor执行"); // TODO 方法执行前要做的事情 //如果说,不执行下面这一行代码,则目标方法将不执行,其他的增强效果也全部失效 Object result= dao.proceed(); // TODO 方法执行后要做的事情 return result; }}
前置代理
/** * 前置增强,也就是说这些代码会在你需要调用的那个方法之前执行 * @author ChenSS * @2017年1月1日 */public class MyMethodBeforeAdvice implements MethodBeforeAdvice{ @Override public void before(Method method, Object[] args, Object target) throws Throwable { System.out.println(method.getName()+"方法执行之前"); }}
后置增强
/** * 后置增强,这些代码会在你需要调用的那个方法之后执行 * @author ChenSS * @2017年1月1日 */public class MyAfterReturningAdvice implements AfterReturningAdvice{ @Override public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable { System.out.println(method.getName()+"方法执行结束"); }}
异常抛出增强
/** * 这个接口实际是一个空的接口,但是方法体还是得参照规范写,具体捕捉什么异常要写清楚 * @author ChenSS * @2017年1月1日 */public class MyThrowsAdvice implements ThrowsAdvice{ /** * 笼统地使用了Exception,可以做具体的异常捕捉 */ public void afterThrowing(Method method, Object[] args, Object target, Exception ex) throws Throwable { System.out.println(method.getName()+"出现异常"); }}
引介增强
/** * 这个呢,也是一种拦截方法,也可以拦截方法的执行, * @author ChenSS * @2017年1月1日 */public class MyIntroductionInterceptor extends DelegatingIntroductionInterceptor{ private static final long serialVersionUID = 2582891122340903718L; public Object invoke(MethodInvocation mi) throws Throwable { System.out.println("引介增强启动拦截"); return super.invoke(mi); }}
测试函数
需要被代理的类,还是我最喜欢的Dao。
/** * 测试用接口 * @author ChenSS * @2017年1月1日 */public interface BaseDao { public long queryId() ; public String queryName();}/** * 测试用Dao * @author ChenSS * @2017年1月1日 */public class UserDao implements BaseDao{ public long queryId() { System.out.println("queryId方法执行中"); System.out.println("故意制造一个算术异常"); return 2/0; } public String queryName() { System.out.println("queryName方法执行中"); return "xiaoming"; }}
主函数
/** * 测试函数 * * @author ChenSS * @2017年1月1日 */public class Test { public static void main(String[] args) { ProxyFactory factory = new ProxyFactory(); // 把我们写的四种代理全部放进去 factory.addAdvice(new MyMethodInterceptor()); factory.addAdvice(new MyMethodBeforeAdvice()); factory.addAdvice(new MyAfterReturningAdvice()); factory.addAdvice(new MyThrowsAdvice()); // 引介增强比较特殊,需要提供接口 factory.addAdvice(new MyIntroductionInterceptor()); factory.setInterfaces(BaseDao.class.getInterfaces()); // 需要代理的那个类 factory.setTarget(new UserDao()); try { UserDao dao = (UserDao) factory.getProxy(); System.out.println(dao.queryName()); System.out.println(); System.out.println(dao.queryId()); } catch (Exception e) { // TODO: handle exception } }}
测试结果如下:
AOP的实战案例介绍
这一部分的内容是后面补充的内容,关于XML配置AOP代理这一块暂时就没办法介绍了。使用XML配置AOP的话,还需要两个Jar包(版本号仅供参考):aopalliance-1.0.jar、aspectjweaver-1.8.3.jar。它主要关注的是方法名,根据方法名做适当的拦截和增强。
AOP典型的使用案例大体有这两个:后台的日志打印、数据库的事务支持。关于日志,大家可以去看一下log4j;至于数据库事务,我给出Hibernate整合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:tx="http://www.springframework.org/schema/tx" xsi:schemaLocation="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/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 配置SessionFactory --> <bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean"> <property name="configLocation" value="hibernate.cfg.xml" /> </bean> <!-- 配置一个事务管理器 --> <bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager"> <property name="sessionFactory" ref="sessionFactory" /> </bean> <!-- 事务管理 --> <aop:config> <aop:pointcut id="txMethod" expression="execution(* com.dao.impl.*Dao.*(..))" /> <aop:advisor advice-ref="txAdvice" pointcut-ref="txMethod" /> </aop:config> <!-- AOP切面声明事务管理 --> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <tx:method name="save*" propagation="REQUIRED" /> <tx:method name="update*" propagation="REQUIRED" /> <tx:method name="add*" propagation="REQUIRED" /> <tx:method name="delete*" propagation="REQUIRED" /> <tx:method name="find*" propagation="SUPPORTS" read-only="true" /> <tx:method name="get*" propagation="SUPPORTS" read-only="true" /> <tx:method name="*" /> </tx:attributes> </tx:advice></beans>
发现研究框架花了太多时间了,原计划年前将Spring框架写清楚,但是发现内容真的好多啊,暂时也只能写到这了,之后我得回归安卓了,做一些安卓的研究,这些天有点荒废安卓了。
各位新年快乐哈,不过文章发表似乎已经1月2号了,O(∩_∩)O哈哈~
- Spring框架——AOP代理
- 黑马程序员—AOP代理以及类似Spring的简单Aop框架
- spring框架学习(八)—静态代理、JDK与CGLIB动态代理、AOP+IoC
- 代理——AOP框架实例
- Spring AOP——Java动态代理
- 《Spring AOP入门——动态代理》
- Spring AOP基础—JDK动态代理
- 【spring框架】利用动态代理实现AOP
- spring框架详解(四)--AOP代理
- (十六)Spring框架——AOP
- Spring框架——AOP前置通知
- spring的AOP学习2——动态代理
- Spring 容器AOP的实现原理——动态代理
- Spring AOP原理——Java中的动态代理机制
- Spring 容器AOP的实现原理——动态代理
- Spring AOP的实现——动态代理机制
- Spring AOP——java的动态代理机制详解
- Spring Aop(十三)——ProxyFactoryBean创建代理对象
- (三)C#之委托和事件
- tomcat 部署项目三种方法
- The constructor ArrayAdapter<String>(XListViewActivity, int, ArrayList<MyData>)
- UI故事版创建简单应用
- android 左边一个listview 点击item去更换右边listview的数据
- Spring框架——AOP代理
- Android 有写入源码的小工具没?
- android消息传递机制
- 自定义控件大全
- can't find compiler executable in your configured search path's for GUN GCC Complier的应对办法
- gridview里用setBackgroundColor改变了子项颜色,滚动后为什么就错乱了。
- Python程序-输出1000以内素数
- 关于addContentView(view, params)
- toolbar伸缩折叠