1.反射是指在程序运行过程中动态获取类的相关信息,包括类是通过哪个加载器进行加载,类的方法和成员变量、构造方法等。
如下示例可以通过三种方法根据类的实例来获取该类的相关信息
1 public static void getClassTest(User user) throws ClassNotFoundException{ 2 //方法一: 3 Class c1 = user.getClass(); 4 //方法二: 5 Class c2 = User.class; 6 //方法三: 7 Class c3 = Class.forName("com.luck.codehelp.entity.User"); 8 System.out.println(c1==c2);//结果为true 9 System.out.println(c1==c3);//结果为true 10 }
这里虽然c1、c2和c3是三个不同的对象,但是都是指向User类的Class对象,而每个User对象的实例的Class对象都是同一个,存在JVM的共享的方法区,所以c1=c2=c3=User.Class
这里通过类的实例来获取类的Class对象的过程就叫做反射;
2.代理是指为某个对象提供一个代理来控制这个对象的访问,以代买火车票为例,定义一个买车票的接口BuyTicketService
personA需要买票,但是想让personB给他代买一下,B先打车去车站,最终购票成功了,然后打车回来,车票上的信息还是personA的信息,在这里
personA是被代理角色,也就是业务逻辑的具体执行者;personB是代理角色,把抽象类或接口定义的方法限制委托给真实主题角色实现(买车票),并在主题角色处理完毕前后做预处理(打车去车站)和善后处理(打车回来)
代码示例如下:
定义一个买票的接口BuyTicketService
1 package com.luck.codehelp.proxy; 2 3 //定义一个serivce 4 public interface BuyTicketService { 5 // 买票的接口 6 public void buyTicket(); 7 }
PersonA实现买票接口
1 public class PersonAServiceImpl implements BuyTicketService { 2 3 @Override 4 public void buyTicket() { 5 System.out.println("我是personA,我买到车票啦"); 6 } 7 8 }
PersonB实现买票接口
1 public class PersonBServiceImpl implements BuyTicketService { 2 3 @Override 4 public void buyTicket() { 5 System.out.println("我是personB,我是帮personA去买票的"); 6 System.out.println("打车去车站"); 7 new PersonAServiceImpl().buyTicket(); 8 System.out.println("打车回去"); 9 } 10 11 }
Main方法测试代码如下:
1 public static void main(String[] args) throws ClassNotFoundException{ 2 //新建personB的实例调用方法 3 buyTicket(new PersonBServiceImpl()); 4 } 5 6 //定义买票方法,参数是买票的接口BuyTicketService 7 public static void buyTicket(BuyTicketService person){ 8 person.buyTicket(); 9 }
结果为:
1 我是personB,我是帮personA去买票的 2 打车去车站 3 我是personA,我买到车票啦 4 打车回去
这是一个最简单的静态代理模式,相当于定义一个接口,代理者和被代理者都实现了该接口,代理者除了实现自身的业务逻辑之外,还将被代理者的实现也一并完成了。
接下来再看看动态代理模式。
动态代理需要调用:java.lang.reflect.Proxy的newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)方法
这个是Proxy类的静态方法,方法的三个参数为
ClassLoader loader:类加载器,目标对象类的类加载器
Class<?>[] interfaces:目标对象实现的接口的类型,使用泛型方式确认类型
InvocationHandler h:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
而一般使用动态代理的时候会为需要代理的目标对象创建一个代理工厂来为其代理,示例如下:
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 import java.lang.reflect.Proxy; 4 5 /** 6 * 代理工厂 7 */ 8 public class ProxyFactory { 9 10 /** 11 * 需要被代理的目标对象 12 */ 13 private Object target; 14 15 public ProxyFactory(Object object){ 16 target = object; 17 } 18 19 /** 20 * 动态给目标对象创建一个代理对象 21 */ 22 public Object getProxyInstance() { 23 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { 24 25 @Override 26 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 27 System.out.println("我是由代理工厂创建来代理target的"); 28 Object result = method.invoke(target, args); 29 System.out.println("代理处理完成"); 30 return result; 31 } 32 }); 33 } 34 }
测试main方法如下:
1 public static void main(String[] args) throws ClassNotFoundException { 2 3 PersonAServiceImpl personA = new PersonAServiceImpl(); 4 BuyTicketService ticketService = (BuyTicketService)new ProxyFactory(personA).getProxyInstance(); 5 ticketService.buyTicket(); 6 }
结果如下:
1 我是由代理工厂创建来代理target的 2 我是personA,我买到车票啦 3 代理处理完成
在这里这个ProxyFactory的目标对象是个Object类型的,所以不仅可以代理PersonAServiceImpl,还可以代理其他的类型的目标对象。比如现在新增一个PersonCServiceImpl如下:
1 public class PersonCServiceImpl implements BuyTicketService { 2 3 @Override 4 public void buyTicket() { 5 System.out.println("我是personC,我买到车票啦"); 6 } 7 }
修改测试的main方法如下:
1 public static void main(String[] args) throws ClassNotFoundException { 2 3 PersonAServiceImpl personA = new PersonAServiceImpl(); 4 PersonCServiceImpl personC = new PersonCServiceImpl(); 5 BuyTicketService ticketServiceA = (BuyTicketService)new ProxyFactory(personA).getProxyInstance(); 6 ticketServiceA.buyTicket(); 7 BuyTicketService ticketServiceC = (BuyTicketService)new ProxyFactory(personC).getProxyInstance(); 8 ticketServiceC.buyTicket(); 9 }
结果为:
1 我是由代理工厂创建来代理target的 2 我是personA,我买到车票啦 3 代理处理完成 4 我是由代理工厂创建来代理target的 5 我是personC,我买到车票啦 6 代理处理完成
但是如过想让这个ProxyFactory只代理PersonAServiceImpl的话,就可以将ProxyFactory的目标对象定义成PersonAServiceImpl如下示例:
1 public class ProxyFactory { 2 3 /** 4 * 需要被代理的目标对象 5 */ 6 private PersonAServiceImpl target = new PersonAServiceImpl(); 7 8 /** 9 * 动态给目标对象创建一个代理对象 10 */ 11 public Object getProxyInstance() { 12 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { 13 14 @Override 15 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { 16 System.out.println("我是由代理工厂创建来代理target的"); 17 Object result = method.invoke(target, args); 18 System.out.println("代理处理完成"); 19 return result; 20 } 21 }); 22 } 23 }
则再次执行测试的main方法,结果就变成:
1 我是由代理工厂创建来代理target的 2 我是personA,我买到车票啦 3 代理处理完成 4 我是由代理工厂创建来代理target的 5 我是personA,我买到车票啦 6 代理处理完成
那么使用代理模式有什么好处呢?
1.首先可以将需要代理的目标对象personAServiceImpl封装起来,而对外服务是代理对象;
2.可以对目标对象进行扩展而不需要改personAServiceImpl本身的业务