静态代理和动态代理

867 阅读4分钟

1.什么是代理

很多人肯定听过和看到过飞机票代理点,火车票代理点。那这些代理点干得事情就是帮航空公司,火车站出售火车票的工作。它们算是一个中间商。实际的服务不是由它们提供。而是由真正的服务商提供。通过这个例子我们可以知道什么是代理:具有目标对象的功能,同时还能对服务进行增强。

2. 什么是静态代理和动态代理?

代理模式是 Java 设计模式,它的特征是代理类与委托类有相同的接口代理类主要负责委托类预处理消息、过滤消息、把消息传递给委托类、以及事后处理消息。代理类与委托类之间捅穿会存在关联关系。一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不是真正服务的实现。而是通过调用委托类的方法来提供相应的服务。这个和上面说的现实生活中的例子完全符合

根据代理的创建时期可以分为两种:

  • 静态代理

    由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。静态代理通常只代理一个类,动态代理是代理一个接口下的多个实现类。静态代理事先知道要代理的是什么。

  • 动态代理

    在程序运行时,运用反射机制动态创建而成。动态代理不知道要代理什么东西,只有在运行时才知道

3. 静态代理

上代码:

public interface TestService {

    void say(String msg);

}
public class TestServiceImpl implements TestService{
    @Override
    public void say(String msg) {
        System.out.println(msg);
    }
}
public class ProxyTestService implements TestService{

    private TestService testService;

    public ProxyTestService(TestService testService) {
        this.testService = testService;
    }

    @Override
    public void say(String msg) {

        //预处理
        System.out.println("before calling say");
        //调用被代理的testService
        testService.say(msg);
        //事后处理
        System.out.println("after calling say");


    }
}

执行:

public class Test {

    public static void main(String[] args) throws Exception{
       TestService service = new TestServiceImpl();
       TestService service1 = new ProxyTestService(service);
       service1.say("ssssssss");
    }

}

通过上面可以看出来静态代理:就是在代理类中进行做数据的前后处理。这里的前后处理就是对功能的增强

4. 动态代理

与静态代理类对照的是动态代理类,动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java反射机制可以生成任意类型的动态代理类。java.lang.reflect 包中的Proxy类和InvocationHandler接口提供了生成动态代理类的能力。

  • JDK原生代理

    上代码:

    public interface TestService {
        void say(String msg);
    }
    
    public class TestServiceImpl implements TestService{
        @Override
        public void say(String msg) {
            System.out.println(msg);
        }
    }
    
    public class TestInvocationHandler implements InvocationHandler {
    
        private Object target;
    
        public TestInvocationHandler(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println(proxy.getClass().getName());
            return method.invoke(target,args);
        }
    }
    
    public class Test {
    
        public static void main(String[] args) throws Exception{
            TestService testService =  (TestService)Proxy.newProxyInstance(Test.class.getClassLoader(), new Class<?>[]{TestService.class}, new TestInvocationHandler(new TestServiceImpl()));
            testService.say("sssss");
        }
    
    }
    
  • cglib代理

public class EnhancerForSampleClassApplication {

    public static void main(String[] args) {

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(A.class);
        enhancer.setCallback(new MxsmPoxy());
        A a = (A)enhancer.create();
        a.aaa("bbb");
    }

   public interface A{

        public void aaa(String aaa);

   }

   public static  class MxsmPoxy implements MethodInterceptor{

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

           System.out.println( method.getName());
           System.out.println(args[0]);
			//这里做什么又实现者来定
           return null;
       }
   }
}

cglib的妙用还可以参照Spring核心包的里面的代码。通过去研究Spring代码对Cglib的使用能够更加清晰的认识。

Tips:RPC的调用很多都是基于动态代理实现的,例如Dubbo。

5. 总结

  • 代理中的功能增强对于静态代理和动态代理上面的代码而言就是打印信息,你不单单能够执行代理的功能还能对其进行其他的操作。
  • 动态代理和静态代理区别在于功能是否编译前就确定了。
  • JDK原生代理只能用于接口,Cglib代理接口和类都可以

我是蚂蚁背大象,文章对你有帮助点赞关注我,文章有不正确的地方请您斧正留言评论~谢谢