前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >代理模式

代理模式

作者头像
OPice
发布2019-12-19 21:26:20
2080
发布2019-12-19 21:26:20
举报
文章被收录于专栏:D·技术专栏D·技术专栏

介绍

  提供一种代理来对原有对象的访问。

  应用实例:Spring AOP、日志、事务控制。

demo

1、定义一个接口和实现

代码语言:javascript
复制
public interface IService {
    /**
     * 获取名称为name 的年龄
     * @param name
     * @return
     */
    public Integer getAge(String name);
}
代码语言:javascript
复制
public class ServiceImpl implements IService {
    @Override
    public Integer getAge(String name) {
        if (Objects.equals("jack",name)){
            return 18;
        } else if (Objects.equals("ma",name)){
            return 24;
        }
        return 20;
    }
}

2、实现接口方法的拦截,打印参数和返回结果等信息

代码语言:javascript
复制
1. JDK 动态代理
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.util.Objects;

@Slf4j
public class MyInvocationHandler implements InvocationHandler {

    private IService iService;

    public MyInvocationHandler(IService iService) {
        this.iService = iService;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (Objects.equals("getAge",method.getName())){

            StopWatch stopWatch = new StopWatch();

            log.info("{}.{} start,args:{}",iService.getClass(),method.getName(),args);
            stopWatch.start();
            int age = (int)method.invoke(iService, args);
            stopWatch.stop();
            log.info("{}.{} end success,execTime:{},result:{}",iService.getClass(),method.getName(),stopWatch.getTime(),age);
        }
        return null;
    }
}
代码语言:javascript
复制
2. CGLIB代理
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.time.StopWatch;
import org.springframework.cglib.proxy.*;

import java.lang.reflect.Method;
import java.util.Objects;

@Slf4j
public class CglibInvocationHandler implements MethodInterceptor {

    private Object target;

    public CglibInvocationHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (Objects.equals("getAge", method.getName())) {

            StopWatch stopWatch = new StopWatch();

            log.info("{}.{} start,args:{}", target.getClass(), method.getName(), objects);
            stopWatch.start();
            int age = (int) method.invoke(target, objects);
            stopWatch.stop();
            log.info("{}.{} end success,execTime:{},result:{}", target.getClass(), method.getName(), stopWatch.getTime(), age);
        }
        return null;
    }

    public static Object getProxy(Object target) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(new CglibInvocationHandler(target));
        return enhancer.create();
    }
}

3、测试

代码语言:javascript
复制
import java.lang.reflect.Proxy;

public class ProxyTest {
    public static void main(String[] args) {
        //jdk 动态代理
        IService iService = new ServiceImpl();
        MyInvocationHandler myInvocationHandler = new MyInvocationHandler(iService);

        IService service = (IService) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{IService.class}, myInvocationHandler);
        service.getAge("jack");

        //cglib 动态代理
       /* IService iService = new ServiceImpl();
        IService service = (IService) CglibInvocationHandler.getProxy(iService);
        service.getAge("jack");*/
    }
}

4、运行结果

image.png

最后

JDK动态代理的对象必须要实现接口,所以对于一些没有实现接口要被代理的对象,不适用JDK动态代理;cglib是通过继承被代理类,重写方法,织入通知通过动态字节码生成代理类,所以被final修饰的类是不能用cglib动态代理的。Spring的动态代理选择的方式也是根据这个条件来的。

代码语言:javascript
复制
// org.springframework.aop.framework.DefaultAopProxyFactory
@Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        }
        else {
            return new JdkDynamicAopProxy(config);
        }
    }
本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 介绍
  • demo
  • 最后
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档