• java 代理的三种实现方式


    Java 代理模式有如下几种实现方式:

      1.静态代理。    

          2.JDK动态代理。

          3.CGLIB动态代理。

    示例,有一个打招呼的接口。分别有两个实现,说hello,和握手。代码如下。

    接口:

    public interface Greeting {
    
        public void doGreet();
    }

    实现类:

    public class SayHello implements Greeting {
    
        @Override
        public void doGreet() {
            System.out.println("Greeting by say 'hello' .");
        }
    
    }
    public class ShakeHands implements Greeting {
    
        @Override
        public void doGreet() {
            System.out.println("Greeting by shake others's hands .");
        }
    
    }
    public class KissHello  {
    
        public void doGreet() {
            System.out.println("Greeting by kiss . ");
        }
    
    }

    在不改变代码的情况下,想在执行目标方法 前后 做一些其他操作。则可以通过代理方式来实现。

    1.静态代理。需要创建代理类。代理类实现了和目标类一样的接口,代理类接收目标类对象,并在实现方法中调用目标类的实现方法前后做手脚。如下:

    public class GreetStaticProxy implements Greeting {
    
        private Greeting hello;//被代理对象
        public GreetStaticProxy(Greeting hello){
            this.hello=hello;
        }
        
        @Override
        public void doGreet() {
            before();//执行其他操作
            this.hello.doGreet();//调用目标方法
            after();//执行其他操作
        }
    
        public void before(){
            System.out.println("[StaticProxy] Come to someone.");
        }
        public void after(){
            System.out.println("[StaticProxy] Back to his own corner");
        }
    }

    测试调用:

    public class Main {
    
        public static void main(String[] args) {
            Greeting hello=new SayHello();
            Greeting shakeHands=new ShakeHands();
            
            //静态代理
            GreetStaticProxy staticHelloProxy=new GreetStaticProxy(hello);
            staticHelloProxy.doGreet();
            System.out.println();
            GreetStaticProxy shakeHandsProxy=new GreetStaticProxy(shakeHands);
            shakeHandsProxy.doGreet();
        }    
    运行结果:
    [StaticProxy] Come to someone. Greeting by say
    'hello' . [StaticProxy] Back to his own corner [StaticProxy] Come to someone. Greeting by shake others's hands . [StaticProxy] Back to his own corner

    这个方式有弊端,如果有N个接口的实现类需要被代理,则需要创建N个代理类。

    2.JDK动态代理

    创建代理类,如下:

    public class JdkProxy implements InvocationHandler {
    
        private Object target;
        
        public JdkProxy(Object obj){
            this.target=obj;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            
            Object result=null;
            before();
            result=method.invoke(target, args);
            after();
            return result;
        }
    
        
        public void before(){
            System.out.println("[JdkProxy] Come to someone.");
        }
        public void after(){
            System.out.println("[JdkProxy] Back to his own corner");
        }
    }

    测试调用:

    public class Main {
    
        public static void main(String[] args) {
            Greeting hello=new SayHello();
            Greeting shakeHands=new ShakeHands();
            
           
            //jdk动态代理
            JdkProxy dynamicProxy=new JdkProxy(hello);
            Greeting target=(Greeting) Proxy.newProxyInstance(hello.getClass().getClassLoader(),
                    hello.getClass().getInterfaces(), dynamicProxy);
            target.doGreet();
            System.out.println();          
            
        }    
        
    }

    这种方式和第一种方式相比,虽然不需要创建很多代理类,

    但是,他依赖与“被代理的对象需要实现接口” 即:在上面给出的代码示例中,动态代理可以代理SayHello和ShakeHands,却不能代理KissHello。因为KissHello没有实现接口。

    3.CGLIB动态代理。

    创建代理类:

    public class CglibProxy implements MethodInterceptor {
    
        public static CglibProxy proxy=new CglibProxy();
        private CglibProxy(){}
        
        public static CglibProxy getInstance(){
            return proxy;
        }
        
        public <T> T getProxy(Class<T> cls){
            return (T) Enhancer.create(cls, this);
        }
        
        @Override
        public Object intercept(Object obj, Method method, Object[] arg,
                MethodProxy proxy) throws Throwable {
            Object result=null;
            try {
                before();
                result= proxy.invokeSuper(obj, arg);
                after();
            } catch (Exception e) {
                e.printStackTrace();
            }
            return result;
        }
    
        public void before(){
            System.out.println("[cglib] Come to someone.");
        }
        public void after(){
            System.out.println("[cglib] Back to his own corner.");
        }
    }

    调用示例:

    public class Main {
    
        public static void main(String[] args) {
            
            //cglib代理
            Greeting targetProxy=CglibProxy.getInstance().getProxy(SayHello.class);
            targetProxy.doGreet();
            System.out.println();
            
            CglibProxy.getInstance().getInstance().getProxy(KissHello.class).doGreet();
            
                   
        }    
    
    }

    综上,CGLIB动态代理最好,spring框架也用到了CGLIB包。

  • 相关阅读:
    字典树略解
    NOIP2018普及组初赛解题报告
    Codeforces 23A You're Given a String...
    远程消息推送的简单方法
    IOS5,6,7的新特性
    面试问题1
    IOS推送消息的步骤
    C面试问题
    label的自适应文本,让文本自适应
    TCP连接的三次握手,TCP/UDP区别联系,socket连接和http连接的区别
  • 原文地址:https://www.cnblogs.com/demingblog/p/5276475.html
Copyright © 2020-2023  润新知