使用JDK创建代理有一个限制,即它只能为接口创建代理,这一点我们从Proxy的接口方法newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)就看得很清楚,第三个入参interfaces就是为代理实例指定的实现接口。虽然,面向接口的编程被很多很有影响力人(包括Rod Johnson)的推崇,但在实际开发中,开发者也遇到了很多困惑:难道对一个简单业务表的操作真的需要创建5个类(领域对象类、Dao接口,Dao实现类,Service接口和Service实现类)吗?对于这一问题,我们还是留待大家进一步讨论。现在的问题是:对于没有通过接口定义业务方法的类,如何动态创建代理实例呢?JDK的代理技术显然已经黔驴技穷,CGLib作为一个替代者,填补了这个空缺
下面得演示还是居于上面一直在使用得例子
1.新建CglibProxy代理类
2.修改MethodAdvice类的invoke方法,添加private MethodProxy porxy;这样一个属性,及其set方法
3.修改Test类,改成使用CglibProxy代理
-
- packagecom.advice;
- importjava.lang.reflect.Method;
- importnet.sf.cglib.proxy.Enhancer;
- importnet.sf.cglib.proxy.MethodInterceptor;
- importnet.sf.cglib.proxy.MethodProxy;
-
-
- publicclassCglibProxyimplementsMethodInterceptor{
- privateMethodAdvicemethodAdvice;
- privateEnhancerenhancer=newEnhancer();
- publicObjectgetBean(StringclassName){
- try{
- enhancer.setSuperclass(Class.forName(className));
- enhancer.setCallback(this);
- returnenhancer.create();
- }catch(Exceptione){
- e.printStackTrace();
- }
- returnnull;
- }
- publicMethodAdvicegetMethodAdvice(){
- returnmethodAdvice;
- }
- publicvoidsetMethodAdvice(MethodAdvicemethodAdvice){
- this.methodAdvice=methodAdvice;
- }
- @Override
- publicObjectintercept(Objectobject,Methodmethod,Object[]args,
- MethodProxyporxy)throwsThrowable{
- methodAdvice.setArgs(args);
- methodAdvice.setMethod(method);
- methodAdvice.setPos(-1);
- methodAdvice.setDone(false);
- methodAdvice.setTarget(object);
- methodAdvice.setPorxy(porxy);
- returnmethodAdvice.proceed();
- }
- }
修改以后的MethodAdvice类的invoke方法
- privateObjectinvoke(){
- done=true;
- try{
- if(porxy!=null){
- returnporxy.invokeSuper(target,args);
- }else{
- returnmethod.invoke(target,args);
- }
- }catch(Exceptione){
- e.printStackTrace();
- }catch(Throwablee){
- e.printStackTrace();
- }
- returnnull;
- }
- packagecom.myadvice.test;
- importcom.advice.CglibProxy;
- importcom.advice.DynaProxy;
- importcom.advice.MethodAdvice;
- importcom.test.BookBiz;
- importcom.test.BookBizImpl;
- publicclassTest{
-
-
- publicstaticvoidmain(String[]args){
-
- CglibProxyproxy=newCglibProxy();
- MethodAdvicemethodAdvice=newMethodAdvice();
- methodAdvice.AddAdvice(newObject[]{newMyAdvice()});
- proxy.setMethodAdvice(methodAdvice);
-
- BookBizImplbookBiz=(BookBizImpl)proxy.getBean(BookBizImpl.class.getName());
- bookBiz.buy("张三","Spring深入潜出",50);
- bookBiz.comment("李四","《恐怖世界》一点都不恐怖,很好看!");
- bookBiz.comment("张三","《Spring深入潜出》还是写得不错的!");
- }
- }
下面是运行结果:
[环绕通知]
前通知,调用的方法:buy,参数:[张三, Spring深入潜出, 50.0]
业务方法buy开始执行
·张三购买图书:Spring深入潜出
·张三增加积分:5
·向物流系统下发货单
业务方法buy结束
后通知,调用的方法:buy,参数:[张三, Spring深入潜出, 50.0]
[环绕通知]
屏蔽李四所有的评论
[环绕通知]
前通知,调用的方法:comment,参数:[张三, 《Spring深入潜出》还是写得不错的!]
业务方法comment开始执行
·张三发表书评《Spring深入潜出》还是写得不错的!
业务方法comment结束
后通知,调用的方法:comment,参数:[张三, 《Spring深入潜出》还是写得不错的!]
通过学习AOP,俺们现在回去想想Spring的数据库事务自动管理是怎么实现的,就比较清晰了,应该使用了环绕通知,在proceed之前开始一个事务,然后在提交事务,就这么简单而已。(^_^,大功告成,关于aop打完收工)