静态代理和动态代理区别:
我们根据加载被代理类的时机不同,将代理分为静态代理和动态代理。①如果我们在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;②如果不能确定,那么可以使用类的动态加载机制,在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制。
代理的优点是在不改变这个方法的前提下去丰富他。这样老功能试用原来的方法也不会有问题,新功能通过代理丰富了原来的方法被广泛试用。
新建一个开发者接口,开发者他会开发code,他会调试debug
public interface Developer { void code(); void debug(); }
新建一个java开发者来实现开发者接口里的code、debug方法
@Data public class JavaDeveloper implements Developer { String name; public JavaDeveloper(String name) { this.name = name; } @Override public void code(){ System.out.println("a code man"); } @Override public void debug(){ System.out.println("a debug man"); } }
进行动态代理使用java开发者开发项目
@RunWith(SpringRunner.class) @SpringBootTest(classes = AdminApplication.class) public class ProxyTest { @Test public void NoProxyTest(){ JavaDeveloper Jack = new JavaDeveloper("Jack"); Jack.code(); Jack.debug(); //打印结果 // a code man // a debug man } @Test public void ProxyTest(){ JavaDeveloper Jack = new JavaDeveloper("Jack"); Developer jackProxy = (Developer) Proxy.newProxyInstance( Jack.getClass().getClassLoader(), Jack.getClass().getInterfaces(), (proxy, method, args) -> { if (method.getName().equals("code")){ System.out.println("Jack proxy code!!"); method.invoke(Jack, args); } if (method.getName().equals("debug")){ System.out.println("Jack proxy debug!!"); return null; } return null; }); jackProxy.code(); jackProxy.debug(); //打印结果 // Jack proxy code!! // a code man // Jack proxy debug!! } }
java.lang.ClassCastException: com.sun.proxy.$Proxy12 cannot be cast to Developer
原因:
对于Spring AOP 采用两种代理方法,一种是常规JDK,一种是CGLIB,当代理对象实现了至少一个接口时,默认使用JDK动态创建代理对象,当代理对象没有实现任何接口时,就会使用CGLIB方法。
解决方法:
Java api代理机制求被代理类必须要实现某个接口。将代理对象转换成接口。
写一个知道代理类的静态代理实现类
public class StaticProxyTest implements Developer{ JavaDeveloper javaDeveloper; public StaticProxyTest(JavaDeveloper javaDeveloper) { this.javaDeveloper = javaDeveloper; } @Override public void code() { System.out.println("ProxyTest sayHello begin"); //在代理类的方法中 间接访问被代理对象的方法 javaDeveloper.code(); System.out.println("ProxyTest sayHello end"); } @Override public void debug() { System.out.println("ProxyTest sayHello begin"); //在代理类的方法中 间接访问被代理对象的方法 javaDeveloper.debug(); System.out.println("ProxyTest sayHello end"); } }
@Test public void staticProxyTest(){ JavaDeveloper javaDeveloper = new JavaDeveloper("Jack"); StaticProxyTest proxyTest = new StaticProxyTest(javaDeveloper); proxyTest.code(); proxyTest.debug(); } //打印 // ProxyTest sayHello begin // a code man // ProxyTest sayHello end // ProxyTest sayHello begin // a debug man // ProxyTest sayHello end
参考:详解java动态代理机制以及使用场景(一)