反射是Java语言的重要特性,它允许程序运行时进行自我检查,也允许对内部的成员 进行操作,能够实现在运行时对类进行装载,使程序运行时更加灵活,但是也有注意正确使用 否则会对性能有影响。
父类
public class Parents { public void function(){ System.out.println("I'm parents!"); } }
子类
public class Children extends Parents{ @Override public void function() { System.out.println("I'm children!");; } }
测试类
import one.Parents;public class TestReflection { @org.junit.Test public void testFunction() throws Exception{ Class cls = Class.forName("one.Children"); Parents parents = (Parents)cls.newInstance(); parents.function(); } }
这时候会调用子类的function方法输出
I'm children!
所以我们可以写一个父类的工厂方法,传入子类的名称,自动调用子类的方法
一些RPC框架就是基于这种动态代理的思想
这里我们增加一个实现类Student
public class Student extends Parents{ @Override public void function() { System.out.println("I'm children!");; } }
增加一个工厂,模拟注册中心,调用子类的方法
public class Factory { private static Map<String, String> map = new HashMap<String, String>(); static{ map.clear(); // 模拟注册中心,存放实现类 map.put("one.Children", "one.Children"); map.put("one.Student", "one.Student"); } public static void main(String[] args) { run("one.Student"); } private static void run(String clzName){ if(null==clzName || clzName.length()==0 || "".equals(clzName)){ System.out.println("参数不能为空"); return; } if(!map.containsKey(clzName)){ System.out.println("参数不合法"); return; } try{ Class cls = Class.forName(map.get(clzName)); Parents parents = (Parents)cls.newInstance(); System.out.println("执行方法"+clzName); parents.function(); }catch (Exception e){ e.printStackTrace(); } } }
运行Factory会出现
执行方法Student
I'm children!
父类接口
public interface Parents { public void function(); }
子类实现
public class Children implements Parents{ @Override public void function() { System.out.println("I'm children!"); } }
基本的代理类,继承InvocationHandler接口,实现invoke方法。
public class Intermediary implements InvocationHandler { private Object post; public Intermediary(Object post) { this.post = post; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object invoke = method.invoke(post, args); System.out.println("代理类:打印日志"); return invoke; } }
优雅的代理类,直接返回对象。采用内部类的方式,将反射的方法当作参数传递给InvocationHandler
public class GetObject { /** * 反射+动态代理的方式调用Parents里面的方法 * @return */ public static void runObject(final Parents post){ // 调用方法时的处理器,本质都是在调用invoke()方法 InvocationHandler h = new InvocationHandler() { /** * 调用方法的处理内容放在invoke里面 * @param proxy 代理对象 * @param method 调用的方法 * @param args 传递的参数 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object invoke = method.invoke(post, args); System.out.println("代理类:打印日志"); return invoke; } }; // 参数:产生这个代理类的classLoader, 实现了这个代理类的接口,h Object o = Proxy.newProxyInstance(Parents.class.getClassLoader(), new Class[]{Parents.class}, h); System.out.println(o.getClass().getName()); System.out.println(o.getClass().getInterfaces()[0]); Parents parents = (Parents) o; parents.function(); return; } }
测试下上述两个类的效果
public class TestIntermediary { public static void main(String[] args) { // 基本的代理类 Parents child = new Children(); Intermediary intermediary = new Intermediary(child); Parents proxy = (Parents) Proxy.newProxyInstance(child.getClass().getClassLoader(), child.getClass().getInterfaces(), intermediary); proxy.function(); // 优雅的代理工具类 GetObject.runObject(new Children()); } }
通过代理类可以在代理类中包装一些方法进去,以下是运行结果
I'm children!
代理类:打印日志
com.sun.proxy.$Proxy0
interface two.Parents
I'm children!
代理类:打印日志
自定义一个服务
public class MyService { public String run(String something){ // int i = 1/0; return "服务正在运行...." + something; } }
定义一个其他服务
public class OtherService { public String runOther(String something){ // int i = 1/0; return "服务正在运行...." + something; } }
写一个服务拦截器,对不是“run”的方法进行拦截
public class ServiceInterceptor implements MethodInterceptor { private static final String INTERCEPTOR = "run"; @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { Object result = null; if(!INTERCEPTOR.equals(methodInvocation.getMethod().getName())){ System.out.println("不能执行该方法" + methodInvocation.getMethod().getName()); return null; } try { System.out.println("方法执行之前:" + methodInvocation.getMethod().toString()); result = methodInvocation.proceed(); System.out.println("方法正常运行结果:" + result); System.out.println("方法执行之后:" + methodInvocation.getMethod().toString()); return result; } catch (Exception e) { System.out.println("方法出现异常:" + e.toString()); System.out.println("方法运行Exception结果:" + result); return result; } } }
public class TestMethodInterceptor { public static void main(String[] args) { ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(new MyService()); proxyFactory.addAdvice(new ServiceInterceptor()); Object proxy = proxyFactory.getProxy(); MyService myService = (MyService) proxy; myService.run("通过代理工厂设置代理对象,拦截代理方法"); proxyFactory.setTarget(new OtherService()); proxy = proxyFactory.getProxy(); OtherService otherService = (OtherService) proxy; otherService.runOther("通过代理工厂设置代理对象,拦截代理方法"); } }
可以看到otherService.runOther方法被拦截了
方法执行之前:public java.lang.String three.MyService.run(java.lang.String) 方法正常运行结果:服务正在运行....通过代理工厂设置代理对象,拦截代理方法 方法执行之后:public java.lang.String three.MyService.run(java.lang.String) 不能执行该方法runOther
定义一个父类实现接口打印
public class BaseService { /** * * @param something * @return */ String run(String something){ return null; } void printLog(){ System.out.println("统一打印日志"); } }
ServiceOne实现上述接口
public class ServiceOne extends BaseService { @Override String run(String something) { return "ServiceOne "+ something; } }
ServiceTwo实现上述接口
public class ServiceTwo extends BaseService{ @Override String run(String something) { return "ServiceTwo "+ something; } }
借助Spring拦截器,实现反射
public class ServiceInterceptor implements MethodInterceptor { private static final String INTERCEPTOR = "printLog"; @Override public Object invoke(MethodInvocation methodInvocation) throws Throwable { Object result = null; try { if(INTERCEPTOR.equals(methodInvocation.getMethod().getName())){ //日志直接打印 result = methodInvocation.proceed(); return result; } System.out.println("方法执行之前:" + methodInvocation.getMethod().toString()); result = methodInvocation.proceed(); System.out.println("方法正常运行结果:" + result); System.out.println("方法执行之后:" + methodInvocation.getMethod().toString()); return result; } catch (Exception e) { System.out.println("方法出现异常:" + e.toString()); System.out.println("方法运行Exception结果:" + result); return result; } } }
定义测试类,调用ServiceOne和ServiceTwo, 把二者的公共方法printLog直接放在test里面调用,反射不会对其执行环绕方法。
public class TestMethodInterceptor { public static void main(String[] args) { ServiceOne serviceOne = (ServiceOne) test(new ServiceOne()); serviceOne.run("通过代理工厂设置代理对象,拦截代理方法"); ServiceTwo serviceTwo = (ServiceTwo) test(new ServiceTwo()); serviceTwo.run("通过代理工厂设置代理对象,拦截代理方法"); } public static BaseService test(BaseService baseService){ ProxyFactory proxyFactory = new ProxyFactory(); proxyFactory.setTarget(baseService); proxyFactory.addAdvice(new ServiceInterceptor()); Object proxy = proxyFactory.getProxy(); BaseService baseProxy = (BaseService) proxy; baseProxy.printLog(); return baseProxy; } }
查看执行结果
统一打印日志
方法执行之前:java.lang.String four.ServiceOne.run(java.lang.String)
方法正常运行结果:ServiceOne 通过代理工厂设置代理对象,拦截代理方法
方法执行之后:java.lang.String four.ServiceOne.run(java.lang.String)
统一打印日志
方法执行之前:java.lang.String four.ServiceTwo.run(java.lang.String)
方法正常运行结果:ServiceTwo 通过代理工厂设置代理对象,拦截代理方法
方法执行之后:java.lang.String four.ServiceTwo.run(java.lang.String)
父接口与原来保持一致
public interface Parents { String hello(String name); }
子类实现接口
public class Children implements Parents { @Override public String hello(String name) { return "I'm " + name; } }
实现基本的代理类
public class Intermediary implements InvocationHandler { private Object post; public Intermediary(Object post) { this.post = post; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object invoke = method.invoke(post, args); System.out.println("代理类:打印日志"); return invoke; } }
调用FastClass实现反射,循环遍历类中的方法执行
public class GetObject { /** * 反射+动态代理的方式调用Parents里面的方法 * @return */ public static Object runObject(final Parents post, String methodName, Object[] parameters){ try { Class<?> clazz = Class.forName(post.getClass().getName()); //获取本类的所有方法,存放入数组 Method[] methods = clazz.getDeclaredMethods(); for (Method method : methods) { if(methodName.equals(method.getName())){ System.out.println("方法名:"+method.getName()); //获取本方法所有参数类型,存入数组 Class<?>[] getTypeParameters = method.getParameterTypes(); if(getTypeParameters.length==0){ System.out.println("此方法无参数"); } for (Class<?> class1 : getTypeParameters) { String parameterName = class1.getName(); System.out.println("参数类型:"+parameterName); } FastClass fastClazz = FastClass.create(Parents.class); int methodIndex = fastClazz.getIndex(method.getName(), getTypeParameters); return fastClazz.invoke(methodIndex, post, parameters); } } } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } return null; } }
执行代理类
public class TestIntermediary { public static void main(String[] args) { // 基本的代理类 Parents child = new Children(); Intermediary intermediary = new Intermediary(child); Parents proxy = (Parents) Proxy.newProxyInstance(child.getClass().getClassLoader(), child.getClass().getInterfaces(), intermediary); System.out.println(proxy.hello("shgx")); // 优雅的代理工具类 System.out.println(GetObject.runObject(new Children(), "hello", new String[]{"shgx"})); } }
执行结果如下:
代理类:打印日志
I'm shgx
方法名:hello
参数类型:java.lang.String
I'm shgx
父类接口
public interface Parents { void function(); }
子类-外部类
public class OuterClass implements Parents{ private Long id; private String name; private Integer sex; private Double age; private Date birthDay; // 省略get set toString方法 @Override public void function() { System.out.println("OuterClass{" + "id=" + id + ", name='" + name + '\'' + ", sex=" + sex + ", age=" + age + ", birthDay=" + birthDay + '}'); } }
子类-内部类
public class InnerClass implements Parents { private Long id; private String name; private Integer sex; private Double age; private Date birthDay; // 新增, 与上面的类形成对比 private String address; // 省略get set toString方法 @Override public void function() { System.out.println("反射实现 InnerClass{" + "id=" + getId() + ", name='" + getName() + '\'' + ", sex=" + getSex() + ", age=" + getAge() + ", birthDay=" + getBirthDay() + ", address='" + address + '\'' + '}'); } }
优雅的代理类实现反射
public class GetObject { /** * 反射+动态代理的方式调用Parents里面的方法 * @return */ public static void runObject(final Parents post){ // 调用方法时的处理器,本质都是在调用invoke()方法 InvocationHandler h = new InvocationHandler() { /** * 调用方法的处理内容放在invoke里面 * @param proxy 代理对象 * @param method 调用的方法 * @param args 传递的参数 * @return * @throws Throwable */ @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object invoke = method.invoke(post, args); return invoke; } }; // 参数:产生这个代理类的classLoader, 实现了这个代理类的接口,h Object o = Proxy.newProxyInstance(Parents.class.getClassLoader(), new Class[]{Parents.class}, h); Parents parents = (Parents) o; parents.function(); } }
实现对象之间的参数拷贝
public class CopyUtil { @SuppressWarnings("unchecked") public static void getClassByBeanUtil(InnerClass dest, OuterClass source) { try { BeanUtils.copyProperties(dest, source); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } System.out.println("BeanUtils result:" + dest); } public static void getClassByPropertyUtil(InnerClass dest, OuterClass source) { try { PropertyUtils.copyProperties(dest, source); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } System.out.println("PropertyUtils result:" + dest); } }
public class TestIntermediary { public static void main(String[] args) { // 基本的代理类 OuterClass outerClass = new OuterClass(1L, "shgx", 1, 23.5, new Date()); // BeanUtil 完成对象拷贝 InnerClass innerClassOne = new InnerClass(); CopyUtil.getClassByBeanUtil(innerClassOne, outerClass); GetObject.runObject(innerClassOne); // PropertyUtil 完成对象拷贝 InnerClass innerClassTwo = new InnerClass(); CopyUtil.getClassByPropertyUtil(innerClassTwo, outerClass); GetObject.runObject(innerClassTwo); // 置空 outerClass.setId(null); outerClass.setName(null); outerClass.setAge(null); outerClass.setSex(null); outerClass.setBirthDay(null); // BeanUtil CopyUtil.getClassByBeanUtil(innerClassOne, outerClass); GetObject.runObject(innerClassOne); // PropertyUtil CopyUtil.getClassByPropertyUtil(innerClassTwo, outerClass); GetObject.runObject(innerClassTwo); } }
执行结果
BeanUtils result:InnerClass{id=1, name='shgx', sex=1, age=23.5, birthDay=Sat Jul 04 18:23:51 CST 2020, address='null'}
反射实现 InnerClass{id=1, name='shgx', sex=1, age=23.5, birthDay=Sat Jul 04 18:23:51 CST 2020, address='null'}
PropertyUtils result:InnerClass{id=1, name='shgx', sex=1, age=23.5, birthDay=Sat Jul 04 18:23:51 CST 2020, address='null'}
反射实现 InnerClass{id=1, name='shgx', sex=1, age=23.5, birthDay=Sat Jul 04 18:23:51 CST 2020, address='null'}
BeanUtils result:InnerClass{id=null, name='null', sex=null, age=null, birthDay=null, address='null'}
反射实现 InnerClass{id=null, name='null', sex=null, age=null, birthDay=null, address='null'}
PropertyUtils result:InnerClass{id=null, name='null', sex=null, age=null, birthDay=null, address='null'}
反射实现 InnerClass{id=null, name='null', sex=null, age=null, birthDay=null, address='null'}
上述方法可以在不同系统之间完成参数传输,实现RPC调用
置空之后在执行发现对象拷贝完成也是null,不会赋予默认值
多余的参数会赋予null值,但是不会删除
使用注解的方式配置日志
@Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface LogAnnotation { /** 日志类型 */ LogTypeEnum logType() default LogTypeEnum.SERVICE_LOG; /** 业务名 */ String bizName() default ""; /** 自定义日志打印*/ Class<? extends LogInfo> customerLogType() default LogInfo.class; /** 是否打印日志*/ boolean recordMonitorData() default false; }
不在展开描述