动态代理的简单代码实现

jdk代理

  • 通常说的动态代理就是指jdk代理。
  • 通过jdk的api在运行期间,动态生成代理对象。
  • 目标对象一定要实现接口。
  • – java.lang.reflect.Proxy
  1. 作用:动态生成代理类和对象
  • – java.lang.reflect.InvocationHandler(处理器接口)
  1. 可以通过invoke方法实现对真实角色的代理访问。
  2. 每次通过Proxy生成代理类对象对象时都要指定对应的处理器对象
interface Star {
    /**
     * 面谈
     */
    void confer();
    /**
     * 签合同
     */
    void signContract();
    /**
     * 订票
     */
    void bookTicket();
    /**
     * 唱歌
     */
    void sing();
    /**
     * 收钱
     */
    void collectMoney();
}

class RealStar implements Star {
    @Override
    public void bookTicket() {
        System.out.println("RealStar.bookTicket()");
    }
    @Override
    public void collectMoney() {
        System.out.println("RealStar.collectMoney()");
    }
    @Override
    public void confer() {
        System.out.println("RealStar.confer()");
    }
    @Override
    public void signContract() {
        System.out.println("RealStar.signContract()");
    }
    @Override
    public void sing() {
        System.out.println("RealStar(周杰伦本人).sing()");
    }
}

class StarHandler implements InvocationHandler {
    Star realStar;
    public StarHandler(Star realStar) {
        super();
        this.realStar = realStar;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object object = null;
        System.out.println("真正的方法执行前!");
        System.out.println("面谈,签合同,预付款,订机票");
        if(method.getName().equals("sing")){
            object = method.invoke(realStar, args);
        }
        System.out.println("真正的方法执行后!");
        System.out.println("收尾款");
        return object;
    }
}

class Client {
    public static void main(String[] args) {
        Star realStar = new RealStar();
        StarHandler handler = new StarHandler(realStar);

        Star proxy = (Star) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
                new Class[]{Star.class}, handler);

        proxy.sing();
    }
}

/*实际生成的代理类
class ProxyStar implements Star {
    StarHandler handler;
    public ProxyStar(StarHandler handler) {
        super();
        this.handler = handler;
    }
    @Override
    public void bookTicket() {
//    handler.invoke(this,当前方法 , args);
    }
    @Override
    public void collectMoney() {
//    handler.invoke(this,当前方法 , args);
    }
    @Override
    public void confer() {
//    handler.invoke(this,当前方法 , args);
    }
    @Override
    public void signContract() {
//    handler.invoke(this,当前方法 , args);
    }
    @Override
    public void sing() {
//    handler.invoke(this,当前方法 , args);
    }
}*/

cglib代理

也叫“子类代理”

当目标对象没有实现接口,就不能使用jdk代理,可以以子类的方式实现。

代理类通过执行回调类的intercept方法来对方法进行代理:

回调类需要实现的接口:MethodInterceptor
实现方法:intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy);
obj : 代理对象
method : 被代理对象的方法
args : 方法的参数
methodProxy : 代理对象的方法(与method的方法不同名,但是有对应关系,其方法实现与被代理对象对应方法的实现一致,而代理对象中与method同名的方法则被改写为:一部分判断逻辑和调用回调对象的intercept方法)

//目标类
class Dao{
    public void save(){
        System.out.println("模拟存储数据");
    }
    public void find(){
        System.out.println("模拟查询数据");
    }
}
//处理拦截器
class HandleInterceptor implements MethodInterceptor{
    Object realDao;
    public HandleInterceptor(Object realDao) {
        super();
        this.realDao = realDao;
    }
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //获取执行方法的方法名(用于判断)
        String methodName = method.getName();
        System.out.println("[---前置代理操作---]");
        Object invoke = method.invoke(realDao, objects);
        System.out.println("[---后置代理操作---]");
        return invoke;
    }
}
//代理工厂
class ProxyFactory {
    //返回目标对象的代理对象
    public static Object getProxyInstance(Object target) {
        //多目标对象生成代理对象
        //1.字节码生成工具
        Enhancer enhancer = new Enhancer();
        //2.设置代理对象的类型
        enhancer.setSuperclass(target.getClass());
        //3.设置回调方法(调用目标方法时触发)
        enhancer.setCallback(new HandleInterceptor(target));
        //4.创建对象并返回
        return enhancer.create();
    }
}
//测试
public class test {
    @Test
    public void test(){
        Dao dao = new Dao();
        Dao proxyInstance = (Dao)ProxyFactory.getProxyInstance(dao);
        proxyInstance.save();
    }
}

 

 

补充:

Cglib两种代理方式:

1、继承非持有式代理

创建代理过程(无需额外创建被代理的对象):
① 创建Enhancer对象 
② 用Enhancer对象设置代理类的父类(被代理类) 
③ 创建回调对象(回调类实现 MethodInterceptor 接口) 
④ 用Enhancer对象设置回调对象 
⑤ 用Enhancer对象创建代理对象

调用方式 :
在回调类的intercept函数中,执行:①前置输出 ②调用被代理对象的方法 ③后置输出 
注意点:② 中需使用 methodProxy 对象调用 invokeSuper 方法即:methodProxy.invokeSuper(obj,args); 参数名意义在上边
 

2、继承持有式代理

创建代理过程 :
① 创建被代理对象 
② 创建回调对象,并将被代理对象存入回调对象的target变量中 
③ 使用Enhancer的create(Class clazz, MethodInterceptor callBack)方法创建代理对象
调用方式 :
在回调类的interpret函数中,执行:①前置输出 ②调用被代理对象的方法 ③后置输出 
注意点:② 中需要使用 method对象调用invoke方法,即:method.invoke(target,args);参数名意义在上边。此处也可执行methodProxy.invokeSuper(obj, args); 但如此调用target对象就变得无意义,而且代理方式同1 继承非持有式代理没有区别了
 

区别:

在代理方式1中,在客户端(main函数)中,生成的代理类调用的方法内部如果有调用该类的方法时,会对被调用的方法进行代理。 
而在代理方式2中,不会。

 

示例:

package com.cglib.test;

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

import java.io.IOException;
import java.lang.reflect.Method;


public class TestMain {

    public static void main(String[] args) throws InterruptedException, IOException {


        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(TestBean.class);
        enhancer.setCallback(new TBProxy());

        TestBean tb1 = (TestBean) enhancer.create();

        TestBean tb2 = (TestBean) Enhancer.create(TestBean.class, new TBProxyx(new TestBean()));

        tb1.print();
        System.out.println("\n\n\n");
        tb2.print();
    }

    // 被代理类
    static class TestBean {


        public void print() {

            System.out.println("i am printing something");
            t();
        }

        public void t() {
            System.out.println("=== im t() ===");
        }
    }
    // 代理方式1
    static class TBProxy implements MethodInterceptor {

        public TBProxy() {
        }

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

            System.out.println("=============  start  ================");

            Object result = methodProxy.invokeSuper(obj, args);
            System.out.println("=============   end   ================");
            return null;
        }
    }
    // 代理方式2
    static class TBProxyx implements MethodInterceptor {

        public TBProxyx(Object obj) {

            this.target = obj;
        }

        Object target;

        public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
            System.out.println("=============  startaaa  ================");
            Object result = method.invoke(target, args);
            System.out.println("=============   endaaa   ================");
            return result;
        }
    }

}

第一种,t()函数的打印结果上下有前后置输出,而第二种没有。

=============  start  ================
i am printing something
=============  start  ================
=== im t() ===
=============   end   ================
=============   end   ================




=============  startaaa  ================
i am printing something
=== im t() ===
=============   endaaa   ================

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值