InvocationHandler动态代理(反射机制) 切面


JDK动态代理,根据实体类生成代理对象,由该实体类的接口变量接收,进而调用接口方法
1,代理对象可以在被代理者代码执行前后增加额外逻辑
2,被代理者发生变化,代理类不需改动
org.apache.ibatis.plugin.Interceptor代理思路:
1,@Intercepts({@Signature(method="prepare",type=StatementHandler.class,args ={Connection.class})}) 
2,针对StatementHandler类prepare方法的调用进行拦截(拦住就返回代理对象,未拦住返回原对象继续执行原对象方法)
3,在代理对象的invoke方法中调用Interceptor的intercept(new Invocation(target, method, args))方法
4,intercept方法对真实对象target处理,最后调用.proceed()方法,进行反射机制调用method.invoke(target, args)

 

抽象角色:声明真实对象和代理对象的共同接口,这样可在任何使用真实对象的地方都可以使用代理对象。
  代理角色:代理对象内部含有真实对象的引用,从而可以在任何时候操作真实对象。代理对象提供一个与真实对象相同的接口,以便可以在任何时候替代真实对象。代理对象通常在客户端调用传递给真实对象之前或之后,执行某个操作,而不是单纯地将调用传递给真实对象,同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
  真实角色:即为代理对象所代表的目标对象,代理角色所代表的真实对象,是我们最终要引用的对象。

https://www.cnblogs.com/LCcnblogs/p/6823982.html

静态代理
interface Subject//抽象角色
{  
    public void doSomething();  
}
class RealSubject implements Subject//真实角色
{  
    public void doSomething()  
  {  
    System.out.println( "call doSomething()" );  
  }  
}
class SubjectProxy implements Subject//代理角色
{
  //代理模式的作用是:为其他对象提供一种代理以控制对这个对象的访问。
  Subject subimpl = new RealSubject();
  public void doSomething()
  {
     System.out.println("before"); //调用目标对象之前可以做相关操作
     subimpl.doSomething();
     System.out.println("after");//调用目标对象之后可以做相关操作
  }
}
 
public class Test
{
    public static void main(String[] args) throws Exception
    {
        Subject sub = new SubjectProxy();
        sub.doSomething();
    }
}

 


可以看到,SubjectProxy实现了Subject接口(和RealSubject实现相同接口),并持有的是Subject接口类型的引用。这样调用的依然是doSomething方法,只是实例化对象的过程改变了,结果来看,代理类SubjectProxy可以自动为我们加上了before和after等我们需要的动作。
如果将来需要实现一个新的接口,就需要在代理类里再写该接口的实现方法,对导致代理类的代码变得臃肿;另一方面,当需要改变抽象角色接口时,无疑真实角色和代理角色也需要改变。

JDK动态代理

interface Subject  
{  
    public void doSomething();  
}
class RealSubject implements Subject  
{  
    public void doSomething()  
  {  
     System.out.println( "call doSomething()" );  
  }  
}
class ProxyHandler implements InvocationHandler
{
    private Object tar;
    //绑定委托对象,并返回代理类
    public Object bind(Object tar)
    {
        this.tar = tar;
        //绑定该类实现的所有接口,取得代理类
        return Proxy.newProxyInstance(tar.getClass().getClassLoader(),
                                      tar.getClass().getInterfaces(),
                                      this);
    }   
    public Object invoke(Object proxy , Method method , Object[] args)throws Throwable//不依赖具体接口实现
    {
        Object result = null;//被代理的类型为Object基类

        String decName = method.getDeclaringClass().getName();//获取接口
        //这里就可以进行所谓的AOP编程了
        //在调用具体函数方法前,执行功能处理
        result = method.invoke(tar,args);
        //在调用具体函数方法后,执行功能处理
        return result;
    }
}
public class Test
{
    public static void main(String args[])
    {
           ProxyHandler proxy = new ProxyHandler();
           //绑定该类实现的所有接口
           Subject sub = (Subject) proxy.bind(new RealSubject());
           sub.doSomething();
    }
}

 


在调用过程中使用了通用的代理类包装了RealSubject实例,然后调用了Jdk的代理工厂方法实例化了一个具体的代理类。最后调用代理的doSomething方法,还有附加的before、after方法可以被任意复用(只要我们在调用代码处使用这个通用代理类去包装任意想要需要包装的被代理类即可)。当接口改变的时候,虽然被代理类需要改变,但是我们的代理类却不用改变了。这个调用虽然足够灵活,可以动态生成一个具体的代理类,而不用自己显示的创建一个实现具体接口的代理类。



切面不能对接口做

org.aspectj.lang.JoinPoint:
<bean class="cn.com.xmh.gcoin.util.AccountTransactionAspect" id="accountTransactionAspect" />
    <aop:config>
    <!-- 定义切面,所有的service的所有方法 ,被MybatisRepository注解标识的
        <aop:pointcut id="txPointcut" expression="execution(* xx.xxx.xxxxxxx.service.*.*(..)) and @annotation(cn.com.xmh.gcoin.MybatisRepository)" />-->
        <aop:pointcut id="txPointcut" expression="execution(* cn.com.xmh.gcoin.logic.impl.QueryUseryTransactionsLogic.*(..)) " />

        <!-- 将切面应用到自定义的切面处理器上,-9999保证该切面优先级最高执行 -->
        <aop:aspect ref="accountTransactionAspect" order="-9999">
            <aop:before method="before" pointcut-ref="txPointcut" />
        </aop:aspect>
    </aop:config>
public class AccountTransactionAspect {
    private Logger logger = LoggerFactory.getLogger(this.getClass().getSimpleName());
     public void before(JoinPoint point) {
           // 获取到当前执行的方法名
           logger.info("****************进入AccountTransactionAspect切面");
           String methodName = point.getSignature().getName();            
            if("insert".equals(methodName)){
                TblAccountTransaction tblAccountTransaction = (TblAccountTransaction)(point.getArgs()[0]);
                tblAccountTransaction.setTbl(ConsistentHashingWithTable.getServer(tblAccountTransaction.getUserNo()));
            }
        }

org.aopalliance.intercept.MethodInterceptor:
<bean class="cn.com.xmh.gcoin.util.ClassInterceptor" id="classInterceptor"></bean>
    <aop:config>
        <!-- 定义切面,所有的service的所有方法 -->
        <aop:pointcut id="classPointcut" expression="execution(* cn.com.xmh.gcoin.logic.impl.QueryUseryTransactionsLogic.*(..)) " />

        <aop:advisor advice-ref="classInterceptor" pointcut-ref="classPointcut" />
        <!-- 将切面应用到自定义的切面处理器上,-9999保证该切面优先级最高执行
        <aop:aspect ref="accountTransactionAspect" order="-9999">
            <aop:before method="before" pointcut-ref="txPointcut" />
        </aop:aspect>-->
    </aop:config>
public class ClassInterceptor  implements MethodInterceptor{  
    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("******"+invocation.getArguments());
        Object result = invocation.proceed();  
        System.out.println("*****");
        return null;
    }  
} 

 


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM