java代理那些事

                                                          代理

代理模式是程序设计中常用的一种模式,通常用于生成一个代理类,间接执行委托类的方法。这样可以很好的保证委托类只实现基本的功能,而不需要和具体的业务产生关联,从而实现代码的高可用性、低耦合性和无代码侵入。为了实现代理类和委托类的行为一致性,他们通常会实现相同的接口。

就像租房的中介一样,房东和中介都有出租房屋的接口。房东的接口中只负责把房子出租出去,然后收房租。不同的中介则会进行不同的代理,有的中介只收取中介费,然后将房子出租;有的中介则将房子稍作装修出租,并且提供了相应的家政服务,不但可以收取中介费还可以收取家政服务费。这个例子生动但是好恶心,对黑中介深恶痛绝,哈哈。

按照代理的创建时期,可以将代理类分为:静态代理和动态代理。

                                             静态代理与动态代理

概念:

静态代理:静态指的是代理类代码是由程序员手动创建或者通过其他工具生成,在程序运行之前通过编译代理类的java文件,就已经生成了.class文件。

动态代理:动态是相对于静态而言,代理类的.class文件在运行前是不存在的,在程序运行时,根据需要动态生成代理类的.class文件。始终没有代理类的java文件。

两者的根本区别:是否拥有代理类的java文件。

 

代码:

  静态代理:

 

    //提供出租的服务接口

   public interface RendService {

 

        void rend();

 

    }

 

    //房东出租房屋的服务实现

    public class RendServiceImpl implements RendService {

 

        @Override

        public void rend() {

            System.out.println("出租房屋,收取房租");

        }

    }

 

 

    //中介提供的出租房屋的中介服务

    public class ProxyRendServiceImpl implements RendService {

 

        private RendService rendService;

 

        public ProxyRendServiceImpl(RendService rendService){

            this.rendService = rendService;

        }

 

        @Override

        public void rend() {

            System.out.println("装修房屋");

            rendService.rend();

            System.out.println("收取家政服务费");

        }

}

 

    //客户端调用

    public class TestStaticProxy {

 

    public static void main(String[] args) {

    RendService rendService = new RendServiceImpl();

         ProxyRendServiceImpl proxy = new ProxyRendServiceImpl(rendService);

         proxy.rend();

     }

    }

 

运行结果:

 

优点:简单明了。

缺点:1、当有多个实现时,会出现大量需要代理的接口,编写大量代理类便成了繁重的工作。2、当出现业务调整,增加或者删除接口时,需要对所有代理类进行修改,造成了维护成本高。

 

 

  动态代理(jdk代理实现):

    //动态代理类

    public class DynamicProxyRendServiceImpl implements InvocationHandler {

 

        private Object targetObject;

 

        public Object newInstance(Object targetObject){

            this.targetObject = targetObject;

            return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);

        }

 

        @Override

        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

            System.out.println("装修房屋");

            Object invoke = method.invoke(targetObject, args);

            System.out.println("收取家政服务费");

            return invoke;

        }

    }

 

    //客户端调用

    public class TestDynamicProxy {

        public static void main(String[] args) {

            RendService rendService = new RendServiceImpl();

            DynamicProxyRendServiceImpl proxyRendService = new DynamicProxyRendServiceImpl();

            RendService proxy = (RendService)proxyRendService.newInstance(rendService);

            proxy.rend();

        }

    }

 

运行结果:

优点:1、对于某一类功能的代理,可以使用同一个动态代理实现,能够减少开发工作量。2、后期维护简单,只需要维护动态代理类。

缺点:动态代理是通过java反射机制发挥作用的,所以理解比较困难。

 

常用于实现日志系统、事务、拦截器、权限控制业务。

 

 

jdk动态代理和cglib动态代理

 

Jdk动态代理:jdk代理要实现InvocationHandler接口,使用Proxy.newInstance()方法创建委托类的代理对象。

Cglib动态代理:cglib代理要实现MethodInterceptor接口,使用Enhancer对象的create()方法创建委托类的代理对象。

两者区别:使用jdk代理的类必须实现接口或者本身就是接口,比如@Service的应用、mybatis的mapper文件是;使用cglib代理的类必须是非final字段修饰的类。因为jdk代理是通过委托类实现的接口生成代理类,而cglib是通过继承委托类产生子类生成代理类。Jdk和cglib分别使用byte[] proxyClassFile = ProxyGenerator.generateProxyClass(proxyName, interfaces)和byte[] bs = DefaultGeneratorStrategy.INSTANCE.generate(enhancer)生成.class文件,然后加载到jvm中,通过java反射机制使用class的构造方法产生代理类实例。

 

Cglib动态代理代码:

cglib 需要的maven配置:

    <dependency>

        <groupId>cglib</groupId>

        <artifactId>cglib</artifactId>

        <version>3.2.6</version>

    </dependency>

 

 

    //cglib代理类

    public class CglibProxyServiceImpl implements MethodInterceptor {

         private Object targetObject;

        public CglibProxyServiceImpl(Object targetObject){

            this.targetObject = targetObject;

        }

        @Override

         public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

            System.out.println("cglib 代理");

            return method.invoke(targetObject, objects);

        }

    }

 

    //cglib客户端调用

    public class TestCglibProxy {

        public static void main(String[] args) {

            RendService rendService = new RendServiceImpl();

            Callback cglib = new CglibProxyServiceImpl(rendService);

            Enhancer enhancer = new Enhancer();

            enhancer.setSuperclass(RendService.class);

            enhancer.setCallback(cglib);

            RendService proxy = (RendService)enhancer.create();

            proxy.rend();

        }

    }

    运行结果:

    

 

更多问题可以加公众号:代码小栈,期待为您解决更多问题

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值