一、简介
jdk的动态代理主要是依靠java反射中的Proxy
类来实现的,且目前jdk的动态代理只能代理接口,无法代理类(因为Proxy.newProxyInstance(loader, interfaces, h)
第二个入参传递的就是接口,反射过来也只能执行对应接口中的方法)。
优缺点
- 优点 能够扩展接口方法的功能,更加解耦,
- 缺点 被代理的真实对象必须要实现接口,否则无法实现动态代理,而且代码编写复杂度相对较高
实现步骤
- (一)创建接口跟真实对象
示例中的接口是Learn接口,真实对象(被代理的对象)是Studentpublic interface Learn { void learn(); } @Component public class Student implements Learn { private String name; private int age; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } @Override public void learn(){ System.out.println(this.name + "学习中"); } public void play(){ System.out.println(this.name + "正在娱乐"); } }
- (二)创建代理对象
public class LearnProxy { /** * 获取代理对象 入参为真实对象所实现的接口 jdk的动态代理只能是代理接口 无法做到基于类的动态代理 * @param learn * @return */ public static Learn getProxyInstance(Learn learn){ ClassLoader loader = learn.getClass().getClassLoader(); //被代理对象的类加载器 Class<?>[] interfaces =learn.getClass().getInterfaces(); //被代理对象实现的接口 InvocationHandler h = new InvocationHandler() { //方法执行器 当调用真实对象所实现的接口的方法时(真实对象的非接口方法是不能被代理的)就会执行invoke方法 /** * proxy 代理对象 是给jdk使用的 自己不需要去动它 * method 是被代理对象将要被执行的方法 * args 是方法的参数 */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("执行方法"+method.getName()+"前的准备工作"); //调用方法前织入的逻辑 Object result = method.invoke(learn, args); //利用反射执行对应的方法 System.out.println("结束方法"+method.getName()+"后的善后工作"); //调用方法后织入的逻辑 return result; //返回方法的执行结果 } }; //生成代理对象并返回 return (Learn) Proxy.newProxyInstance(loader, interfaces, h); } }
- (三)测试类
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = "classpath:application.xml") public class DynamicProxyTest { @Autowired private Student student; @Test public void test(){ Learn studentProxy = LearnProxy.getProxyInstance(student); //获得代理对象 生成代理对象 studentProxy.learn(); } }