aop的两种实现方式

 AOP,面向切面编程,可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。  
  Aspect Oriented Programming(AOP),是目前软件开发中的一个热点,也是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
  有两种方式可以实现aop,一种是根据利用jdk自带的proxy,另外一种是利用cglib的proxy.
  一 jdk代理
    JDK的动态代理主要涉及到java.lang.reflect包中的两个类:Proxy和InvocationHandler。其中 InvocationHandler是一个接口,可以通过实现该接口定义横切逻辑,在并通过反射机制调用目标类的代码,动态将横切逻辑和业务逻辑编织在一起。
自定义一个接口
public interface TestInterface {
    public void insert();

}
实现接口
public class TestImpl implements TestInterface{

    @Override
    public void insert() {
        // TODO Auto-generated method stub
        System.out.println("插入数据");
        
    }

}

创建jdk动态代理的工厂类
public class JdkDymanicProxyFactory implements InvocationHandler{
    
    private Object targetObject;
    public Object createProxyFactory(Object target){
        this.targetObject = target;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);
    }

    //执行方法的时候回去回调这个函数
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        // TODO Auto-generated method stub
        //在这里做一下日记
        System.out.println("execute:"+method.getName());
        return method.invoke(targetObject, args);
    }

}

测试执行结果
package com.lwq;
/**
 * @author thomaslwq 
 * @version 创建时间:Sep 17, 2012 8:56:20 AM
 * 类说明 利用jdk的动态代理实现aop
 */


public class JdkProxyTest {
    
    public static void main(String args[]){
        
        JdkDymanicProxyFactory jdpf = new JdkDymanicProxyFactory();
        TestInterface ti = (TestInterface) jdpf.createProxyFactory(new TestImpl());
        ti.insert();
    }

}
运行结果如下:
execute:insert
插入数据

二 利用cglib代理实现aop

CGlib是一个强大的,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。  CGLIB是针对类实现代理的,主要对指定的类生成一个子类,并覆盖其中的方法, 因为是继承,所以不能使用final来修饰类或方法 。和jdk代理实现不同的是,cglib不要求类实现接口。
即你可以直接编出一个类:
public class CglibTestImpl {
    public void insert() {
        // TODO Auto-generated method stub
        System.out.println("插入数据");
        
    }

}
然后创建cglib代理的工厂类:
package com.lwq;

import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

/**
 * @author thomaslwq 
 * @version 创建时间:Sep 17, 2012 9:24:23 AM
 * 类说明
 */
public class CglibProxyFactory implements MethodInterceptor{
    
    private Object targetObject;
    public Object createProxyInstance(Object target){
        this.targetObject = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.targetObject.getClass());
        //设置回调函数
        enhancer.setCallback(this);
        return enhancer.create();
        
    }

    @Override
    public Object intercept(Object obj, Method method, Object[] args,
            MethodProxy proxy) throws Throwable {
        // TODO Auto-generated method stub
        System.out.println("record:"+method.getName());
        System.out.println("Object:"+obj.getClass());
        System.out.println("targetObject:"+targetObject.getClass());
        return method.invoke(targetObject, args);
    }

}
最后写一个测试类:
package com.lwq;
/**
 * @author thomaslwq 
 * @version 创建时间:Sep 17, 2012 9:29:21 AM
 * 类说明
 */
public class CglibProxyTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        CglibProxyFactory cpf = new CglibProxyFactory();
        //没有实现接口
        CglibTestImpl ti = (CglibTestImpl)cpf.createProxyInstance(new CglibTestImpl());
        ti.insert();
    }

}
测试结果如下:
record:insert
插入数据


JDK动态代理和CGLIB字节码生成的区别? 
* JDK动态代理只能对实现了接口的类生成代理,而不能针对类 
* CGLIB是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法 

  因为是继承,所以该类或方法最好不要声明成final 




SPRING是通过动态代理来实现AOP的,SPRING内部提供了2种实现机制
1.如果是有接口声明的类进行AOP,spring调用的是java.lang.reflection.Proxy类来做处理

org.springframework.aop.framework.JdkDynamicAopProxy

       public Object getProxy(ClassLoader classLoader) {

              if (logger.isDebugEnabled()) {

                     Class targetClass = this.advised.getTargetSource().getTargetClass();

                     logger.debug(“Creating JDK dynamic proxy” +

                                   (targetClass != null ? ” for [" + targetClass.getName() + "]” : “”));

              }

              Class[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);

              return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

       }

org.springframework.aop.framework.ReflectiveMethodInvocation

public Object proceed() throws Throwable {

              //     We start with an index of -1 and increment early.

              if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() – 1) {

                     return invokeJoinpoint();

              }

              Object interceptorOrInterceptionAdvice =

                  this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);

              if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {

                     // Evaluate dynamic method matcher here: static part will already have

                     // been evaluated and found to match.

                     InterceptorAndDynamicMethodMatcher dm =

                         (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;

                     if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {

                            return dm.interceptor.invoke(this);

                     }

                     else {

                            // Dynamic matching failed.

                            // Skip this interceptor and invoke the next in the chain.

                            return proceed();

                     }

              }

              else {

                     // It’s an interceptor, so we just invoke it: The pointcut will have

                     // been evaluated statically before this object was constructed.

                     return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);

              }

       }

2.如果是没有接口声明的类呢?SPRING通过CGLIB包和内部类来实现

private static class StaticUnadvisedInterceptor implements MethodInterceptor, Serializable {

 

private final Object target;

 

public StaticUnadvisedInterceptor(Object target) {

this.target = target;

}

 

public Object intercept(Object proxy, Method method, Object[] args,

MethodProxy methodProxy) throws Throwable {

 

Object retVal = methodProxy.invoke(target, args);

return massageReturnTypeIfNecessary(proxy, target, retVal);

}

}

 

 

/**

* Method interceptor used for static targets with no advice chain, when the

* proxy is to be exposed.

*/

private static class StaticUnadvisedExposedInterceptor implements MethodInterceptor, Serializable {

 

private final Object target;

 

public StaticUnadvisedExposedInterceptor(Object target) {

this.target = target;

}

 

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

Object oldProxy = null;

try {

oldProxy = AopContext.setCurrentProxy(proxy);

Object retVal = methodProxy.invoke(target, args);

return massageReturnTypeIfNecessary(proxy, target, retVal);

}

finally {

AopContext.setCurrentProxy(oldProxy);

}

}

}

 

 

/**

* Interceptor used to invoke a dynamic target without creating a method

* invocation or evaluating an advice chain. (We know there was no advice

* for this method.)

*/

private class DynamicUnadvisedInterceptor implements MethodInterceptor, Serializable {

 

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

Object target = advised.getTargetSource().getTarget();

try {

Object retVal = methodProxy.invoke(target, args);

return massageReturnTypeIfNecessary(proxy, target, retVal);

}

finally {

advised.getTargetSource().releaseTarget(target);

}

}

}

 

 

/**

* Interceptor for unadvised dynamic targets when the proxy needs exposing.

*/

private class DynamicUnadvisedExposedInterceptor implements MethodInterceptor, Serializable {

 

public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

Object oldProxy = null;

Object target = advised.getTargetSource().getTarget();

try {

oldProxy = AopContext.setCurrentProxy(proxy);

Object retVal = methodProxy.invoke(target, args);

return massageReturnTypeIfNecessary(proxy, target, retVal);

}

finally {

AopContext.setCurrentProxy(oldProxy);

advised.getTargetSource().releaseTarget(target);

}

}

}

 

我们自己也可以来试试
1.jdk proxy方式

先来一个接口
IHelloWorld.java

package kris.aop.test;

 

public interface IHelloWorld {

 

public void print(String name);

public void write(String sth);

}

 

再来一个实现

HelloWorld.java

package kris.aop.test;

 

public class HelloWorld implements IHelloWorld {

 

public void print(String name){

System.out.println(“HelloWorld “+name);

}

 

public void write(String sth) {

System.out.println(“write “+sth);

}

 

}

 

代理类

DefaultInvocationHandler.java

package kris.aop.test;

 

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

 

public class DefaultInvocationHandler implements InvocationHandler {

 

/**

* 替换外部class调用的方法

* obj                 外部已经已经包装好InvocationHandler的实例

* method        外部方法

* args              方法参数

*/

public Object invoke(Object obj, Method method, Object[] args)

throws Throwable {

String s1 []={“kris”};

String s2 []={“anyone”};

IHelloWorld ihw=new HelloWorld();

System.out.println(“start!”);

method.invoke(ihw,args);

method.invoke(ihw,s1);

Object o=method.invoke(ihw,s2);

System.out.println(“stop!”);

return o;

}

}

 

测试类
Test.java

package kris.aop.test;

 

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Proxy;

 

public class Test {

 

public static void main(String args []){

Class clazz = new HelloWorld().getClass();

ClassLoader cl = clazz.getClassLoader();

Class classes [] = clazz.getInterfaces();

InvocationHandler ih=new DefaultInvocationHandler();

//用InvocationHandler给HelloWorld进行AOP包装

IHelloWorld ihw=(IHelloWorld) Proxy.newProxyInstance(cl,classes,ih);

ihw.print(“test”);

ihw.write(“test”);

}

}

 

2.用CGLIB包实现,首先不要忘了引入那个包

package kris.aop.cglib.test;

 

public class HelloWorld {

 

public void print(String name){

System.out.println(“HelloWorld “+name);

}

 

public void write(String sth) {

System.out.println(“write “+sth);

}

public void print(){

System.out.println(“HelloWorld”);

}

}

 

代理类(没用内部类,看起来清楚点)

package kris.aop.cglib.test;

 

import java.lang.reflect.Method;

 

import net.sf.cglib.proxy.MethodInterceptor;

import net.sf.cglib.proxy.MethodProxy;

 

public class MethodInterceptorImpl implements MethodInterceptor {

 

public Object intercept(Object obj, Method method, Object[] args,

MethodProxy proxy) throws Throwable {

 

System.out.println(method);

 

proxy.invokeSuper(obj, args);

 

return null;

}

}

 

测试类

 

package kris.aop.cglib.test;

 

import net.sf.cglib.proxy.Enhancer;

 

public class Test {

 

public static void main(String[] args) {

 

Enhancer enhancer = new Enhancer();

 

enhancer.setSuperclass(HelloWorld.class);

//设置回调方法实现类

enhancer.setCallback(new MethodInterceptorImpl());

//实例化已经添加回调实现的HELLOWORLD实例

HelloWorld my = (HelloWorld) enhancer.create();

 

my.print();

}

 

}


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值