静态代理和动态代理原理及实现

Posted fantongxue

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了静态代理和动态代理原理及实现相关的知识,希望对你有一定的参考价值。

@(静态代理(Static Proxy)和动态代理(Dynamic Proxy))

静态代理

静态代理要先抽象出一个接口,并且写一个实现类实现这个接口。

//主业务接口
public interface SomeService {
String first();
String second();
}
//目标类
public class SomeServiceImpl implements SomeService{

    public String first() {
        // TODO Auto-generated method stub
        return "I Love You";
    }

    public String second() {
        // TODO Auto-generated method stub
        return "China";
    }

}

然后写静态代理类,要求静态代理类要求目标类共同实现主业务接口 。这里的代理类实现的是把目标类的某些方法的返回值变成大写。

public class SomeServiceProxy implements SomeService{
    private SomeService target;
    //提供无参构造器和带参构造器传递方法
    public SomeServiceProxy(){
        super();
    }
    public SomeServiceProxy(SomeService target) {
        super();
        this.target = target;
    }
    public String first() {
        // TODO Auto-generated method stub
        return target.first();//正常输出
    }
    public String second() {
        // TODO Auto-generated method stub
        return target.second().toUpperCase();//变大写
    }
}

写一个测试类

public class MyTest {
public static void main(String args[]){
    //定义目标对象
    SomeService target=new SomeServiceImpl();
    //定义目标对象的代理对象,把目标对象传进去
    SomeService serviceProxy=new SomeServiceProxy(target);
    String result1=serviceProxy.first();
    String result2=serviceProxy.second();
    System.out.println(result1+","+result2);
}
}

执行结果
技术图片
执行了代理类之后,second方法的返回值变成了大写。

jdk动态代理

首先jdk动态代理和静态代理一样,都需要先抽象出来一个接口并实现这个接口。

//主业务接口
public interface SomeService {
String first();
String second();
}
//目标类
public class SomeServiceImpl implements SomeService{
    public String first() {
        // TODO Auto-generated method stub
        return "I Love You";
    }
    public String second() {
        // TODO Auto-generated method stub
        return "China";
    }
}

然后写测试类,动态代理在测试类中创建(Proxy类的newProxyInstance方法)

public class MyTest {
public static void main(String args[]){
    //定义目标对象
    final SomeService target=new SomeServiceImpl();
    //定义目标对象的代理对象
    SomeService serviceProxy=(SomeService)Proxy.newProxyInstance(
            target.getClass().getClassLoader(),//第一个参数:目标类的类加载器
            target.getClass().getInterfaces(),//第二个参数:目标类所实现的所有接口
            new InvocationHandler() {       //第三个参数:内部匿名类
                /**
                 * 增强就在这里完成
                 * proxy:代理对象
                 * method:目标方法
                 * args:目标方法的参数列表
                 */
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
                    // 内部类使用外部类的成员变量,外部类的成员变量必须声明为final类型,否则报错
                    Object result = method.invoke(target, args);
                    //指定操作的是哪个方法
                    if ("second".equals(method.getName())) {
                        result = ((String) result).toUpperCase();
                    }
                    return result;
                }
            });
    String result1=serviceProxy.first();
    String result2=serviceProxy.second();
    System.out.println(result1+","+result2);
}
}

执行结果
技术图片
second方法的返回值也变成了大写。

CGLIB动态代理

使用JDK的Proxy实现代理,要求目标类和代理类实现相同的接口,若目标类不存在接口,则无法使用该方式实现。对于无接口的类,要为其创建动态代理,就要使用CGLIB实现。CGLIB代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。
所以,使用CGLIB动态代理,要求目标类必须能够被继承,即不能是final的类。

CGLIB是一个外部项目,首先要导入jar包
技术图片

这里不需要抽象一个接口,只写一个主业务类。

//主业务类
public class SomeService {
    public String first() {
        // TODO Auto-generated method stub
        return "I Love You";
    }

    public String second() {
        // TODO Auto-generated method stub
        return "China";
    }
}

然后写一个CGLIB动态代理创建工厂

//要实现MethodInterceptor方法,返回的类型是回调函数,所以cglib_ProxyFactory 类本身也为回调函数对象
public class cglib_ProxyFactory implements MethodInterceptor{
    private SomeService target;
    public cglib_ProxyFactory() {
        super();
        // TODO Auto-generated constructor stub
    }
    public cglib_ProxyFactory(SomeService target) {
        super();
        this.target = target;
    }
    //用于创建cglib代理对象
    public SomeService myProxyCreator(){
        //增强器
        Enhancer enhancer=new Enhancer();
        //指定父类,即要增强的目标类
        enhancer.setSuperclass(SomeService.class);
        //指定回调函数对象
        enhancer.setCallback(this);
        //创建cglib代理对象
        return (SomeService) enhancer.create();
    }
public Object intercept(Object obj, Method method, Object[] args,
        MethodProxy proxy) throws Throwable {
    Object result = method.invoke(target, args);
    if ("second".equals(method.getName())) {
        result = ((String) result).toUpperCase();
    }
    return result;
}
}

再写一个测试类

public class MyTest {
public static void main(String args[]){
    //定义目标对象
    final SomeService target=new SomeService();
    //定义目标对象的代理对象
    SomeService serviceProxy=new cglib_ProxyFactory(target).myProxyCreator();
    String result1=serviceProxy.first();
    String result2=serviceProxy.second();
    System.out.println(result1+","+result2);
}
}

执行结果
技术图片
second方法的返回值也变成了大写。

以上是关于静态代理和动态代理原理及实现的主要内容,如果未能解决你的问题,请参考以下文章

设计模式----代理模式

JDK动态代理和cglib动态代理(AOP的底层实现原理)

什么是反射技术?什么是静态代理?什么是动态代理?什么是aop

java有关静态代理及动态代理的实现

Java中动态代理实现原理深究

06设计模式-代理模式