静态代理的缺点
当我们的目标类多个方法时,使用静态代理就需要为这多个方法写差不多的操作,这样会使得我们的代码变的越来越臃肿。我们就可以使用动态代理的方式来处理这个问题
动态代理
动态代理的两种实现方法:基于接口的代理使用jdk的方式,基于继承的代理使用cglib
jdk动态代理
Jdk动态代理只能代理实现接口的类,没有实现接口的类不能实现JDK的动态代理。
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
(1)Interface InvocationHandler :该接口中仅定义了一个方法public object invoke(Object obj;Method method, Object[] args)在实际使用时,第一个参数obj一般是指代理类, method是被代理的方法, args为该方法的参数数组。 这个抽象方法在代理类中动态实现。
(2)Proxy :该类即为动态代理类
newProxyInstance方法用来返回一个代理对象,这个方法总共有3个参数,
- ClassLoader loader:一个ClassLoader对象,定义了由哪个ClassLoader对象来对生成的代理对象进行加载
- Class<?>[] interfaces:一个Interface对象的数组,表示的是我将要给我需要代理的对象提供一组什么接口,如果我提供了一组接口给它,那么这个代理对象就宣称实现了该接口(多态),这样我就能调用这组接口中的方法了
- InvocationHandler h:一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
案例
接口
public interface Subject { void work(); }
真实对象
public class RealSubject implements Subject{ @Override public void work() { System.out.println("----------吃饭"); } }
jdk动态代理类
public class JdkProxySubject implements InvocationHandler { private RealSubject realSubject; public JdkProxySubject(RealSubject realSubject) { this.realSubject = realSubject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("------买菜"); Object result=null; try { result = method.invoke(realSubject,args); } catch (Exception e) { e.printStackTrace(); } finally { System.out.println("------洗碗"); } return result; } }
客户端调用
public class Client { public static void main(String[] args) { Subject subject = (Subject) Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), new JdkProxySubject(new RealSubject())); subject.work(); } }
- RealSubject.class.getInterfaces() 该方法是获取到RealSubject实现的接口,如果有RealSubject实现多个接口都可通过该方法获取到。
- RealSubject.class.getInterfaces()可以替换成
new Class[]{Subject.class}
的效果是一样的
效果
cglib动态代理
注意事项:
- cglib是通过继承来实现动态代理的
- 无法对static,final类进行代理
- 无法对private,static方法进行代理
案例
真实对象,不需要接口
public class RealSubject{ public void work() { System.out.println("----------cglib---吃饭"); } }
代理对象
public class DemoMethodInterceptor implements MethodInterceptor{ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before in cglib------买菜"); Object result = null; try{ result = proxy.invokeSuper(obj, args); }catch (Exception e){ System.out.println("get ex:"+e.getMessage()); throw e; }finally { System.out.println("after in cglib------洗碗"); } return result; } }
客户端调用
public class Client { public static void main(String[] args){ Enhancer enhancer = new Enhancer(); //真实对象(代理对象需要去继承这个对象) enhancer.setSuperclass(RealSubject.class); //设置回调方法,也就是我们需要植入的代码 enhancer.setCallback(new DemoMethodInterceptor()); //创建新的代理对象 RealSubject subject = (RealSubject) enhancer.create(); //执行代理对象的方法 subject.work(); } }