我们可能都用过 Spring AOP ,底层的实现原理是怎样的呢?java
反射经常使用于编写工具,企业级开发要用到的 Mybatis、Spring 等框架,底层的实现都用到了反射。能用好反射,就能提升咱们编码的核心能力。框架
JAVA反射机制是在运行状态中,对于任意一个实体类,都可以知道这个类的全部属性和方法;对于任意一个对象,都可以调用它的任意方法和属性。ide
做用:函数
经常使用的类:工具
Class 类的实例表示正在运行的 Java 应用程序中的类和接口,Class 没有公共构造方法,Class 对象是在加载类时由 Java 虚拟机及经过调用类加载器中的 defineClass 方法自动构造的。测试
获取 Class 对象有4种方式,前三种比较经常使用。this
首先建立一个类用于测试编码
package com.jikedaquan.reflection; public class User { private int id; private String username; private String password; public User() { } public User(int id, String username, String password) { super(); this.id = id; this.username = username; this.password = password; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public void show() { System.out.println("Hello"); } @Override public String toString() { return "User [id=" + id + ", username=" + username + ", password=" + password + "]"; } }
编写测试代理
package com.jikedaquan.reflection; public class GetClass { public static void main(String[] args) { //方法1 try { Class clz1=Class.forName("com.jikedaquan.reflection.User"); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("找不到指定类"); } //方法2 Class clz2=User.class; //方法3 User user=new User(); Class clz3=user.getClass(); //方法4 类的加载器 try { Class clz4=GetClass.class.getClassLoader().loadClass("com.jikedaquan.reflection.User"); } catch (ClassNotFoundException e) { e.printStackTrace(); System.out.println("找不到指定类"); } } }
方法1语法:
Class Class对象 = Class.forName(包名+类名);
code
方法2语法:
Class Class对象 = 类名.class;
方法3语法:
Class Class对象 = 对象.getClass();
getClass() 方法是从 Object 类中继承过来的
Class 类经常使用方法
方法名称 | 说明 |
---|---|
Annotation[] getAnnotations() | 返回此元素上存在的全部注解 |
Constructor
|
获取指定参数的构造函数 |
Constructor<?>[] getConstructors() | 返回包含的公有构造方法 |
Constructor<?>[] getDeclaredConstructors() | 返回全部构造方法 |
Field getDeclaredField(String name) | 返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段 |
Method getDeclaredMethod(String name, Class<?>... parameterTypes) | 根据方法名和参数获取方法对象 |
API 中能够看到有两种获取结构的方式:getDeclaredXxx()和getXxx();getDeclaredXxx()能够获取全部包括私有的
获取类的结构
package com.jikedaquan.reflection; import java.lang.annotation.Annotation; import java.lang.reflect.Constructor; import java.lang.reflect.Field; import java.lang.reflect.Method; public class GetClassStruct { public static void main(String[] args) { try { Class clz=Class.forName("com.jikedaquan.reflection.User"); System.out.println("===========构造==========="); //获取构造方法 Constructor[] cons=clz.getDeclaredConstructors(); for (Constructor constructor : cons) { System.out.println(constructor); } //获取字段 System.out.println("===========字段==========="); Field[] fields=clz.getDeclaredFields(); for (Field field : fields) { System.out.println(field); } //获取方法 System.out.println("===========方法==========="); Method[] methods=clz.getDeclaredMethods(); for (Method method : methods) { System.out.println(method); } //获取父类 System.out.println("===========父类==========="); Class supperClass=clz.getSuperclass(); System.out.println(supperClass.getName()); //获取实现的接口 System.out.println("===========接口==========="); Class[] interfaces=clz.getInterfaces(); for (Class interf : interfaces) { System.out.println(interf); } //获取注解 System.out.println("===========注解==========="); Annotation[] annotations=clz.getAnnotations(); for (Annotation annotation : annotations) { System.out.println(annotation); } } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
注意:jdk1.9弃用此方式实例化对象
Object obj=clz.newInstance();
经过反射获取有参或无参构造后方可实例化化对象
package com.jikedaquan.reflection; import java.lang.reflect.Constructor; public class CallConstructor { public static void main(String[] args) { //获取User 的 Class Class<User> clz=User.class; //获取无参构造方法并实例化 try { //getConstructor()方法不传参即无参 Constructor<User> constructor=clz.getConstructor(); User user=constructor.newInstance(); System.out.println(user); } catch (Exception e) { e.printStackTrace(); } //获取有参构造方法并实例化 try { Constructor<User> constructor=clz.getConstructor(int.class,String.class,String.class); User user=constructor.newInstance(18,"张三","abc123"); System.out.println(user); } catch (Exception e) { e.printStackTrace(); } } }
获取指定构造方法时,第二个参数为动态参数,不填写即获取无参构造方法,填写指定个数和指定类型.class可获取对应方式的构造方法。
package com.jikedaquan.reflection; import java.lang.reflect.Method; public class CallMethod { public static void main(String[] args) { //获取User 的 Class Class<User> clz=User.class; //获取无参方法 show try { Method method=clz.getMethod("show"); //执行clz中的方法 method.invoke(clz.getConstructor().newInstance()); } catch (Exception e) { e.printStackTrace(); } //获取一个参数为String的方法 try { Method method=clz.getMethod("setUsername", String.class); //反射实例化对象 User user=clz.getConstructor().newInstance(); //执行这个对象的方法 method.invoke(user, "反射"); //测试结果 System.out.println(user); } catch (Exception e) { e.printStackTrace(); } } }
若是有多个参数,获取方法:
getMethod("方法名称",参数1.class,参数2.class,参数3.class)
多个参数执行时:
method.invoke(对象,参数1,参数2,参数3);
动态代理是指客户经过代理类来调用其余对象的方法,而且是在程序运行时根据须要建立目标类的代理对象。
原理:
使用一个代理将对象包装起来,而后用该代理对象取代原对象,任何对原始对象的调用都要经过dialing,代理对象决定是否以及什么时候将方法调用转到原始对象上。
生活中海外代购其实就用到了代理,你可能不方便出国,可是代购能够,最终帮你完成购买行为。
以代购为例子完成静态代理
package com.jikedaquan.reflection; //购买接口(约定) interface Buy{ void buyProduct(); } //被代理的 class Customer implements Buy{ @Override public void buyProduct() { System.out.println("购买商品"); } } //代理 class ProxyBuy implements Buy{ private Customer customer; public ProxyBuy(Customer customer) { this.customer=customer; } @Override public void buyProduct() { System.out.println("代理:出国"); //被代理的对象的行为 customer.buyProduct(); System.out.println("代理:回国"); } } public class TestStaticProxy { public static void main(String[] args) { Customer customer=new Customer(); ProxyBuy proxyBuy=new ProxyBuy(customer); proxyBuy.buyProduct(); } }
那么动态代理意味着不能只代理 Customer 类的行为,还能够代理其余类的行为
package com.jikedaquan.reflection; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; //工厂接口 interface Factory{ void product(); } //电脑工厂 class ComputerFactory implements Factory{ @Override public void product() { System.out.println("生产电脑"); } } //动态代理处理器 class MyInvocationHandler implements InvocationHandler{ //要被代理的对象 private Object proxyObj; //产生代理对象 public Object bind(Object proxyObj) { this.proxyObj=proxyObj; return Proxy.newProxyInstance( proxyObj.getClass().getClassLoader(), proxyObj.getClass().getInterfaces(), this ); } //代理对象实际执行的方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("代理:收收费"); Object result=method.invoke(proxyObj, args); System.out.println("代理:代理完成"); return result; } } public class TestDynamicProxy { public static void main(String[] args) { //建立代理对象生产器 MyInvocationHandler invocationHandler=new MyInvocationHandler(); //建立要被代理的对象 ComputerFactory computerFactory=new ComputerFactory(); //生产代理对象 Object factoryProxy=invocationHandler.bind(computerFactory); Factory factory=(Factory) factoryProxy; factory.product(); //建立另外一个要被代理的对象(上个示例静态代理的对象和接口) Customer customer=new Customer(); //生产代理对象 Object buyProxy=invocationHandler.bind(customer); Buy buy=(Buy) buyProxy; buy.buyProduct(); } }
在 main 方法中,建立了一个 MyInvocationHandler 对象,经过 bind 方法能够传入任意要被代理的对象,实现了动态。
重点来了,拿好小本子笔记!!!!!
实现动态代理的步骤:
1.建立要被代理的类的接口
2.建立要被代理的类实现类
3.建立代理对象处理器(MyInvocationHandler),实现 InvocationHandler 接口
4.编写生产代理对象的方法,方法内调用 Proxy.newInstance() 方法,返回代理对象
5.重写 InvocationHandler 的 invoke 方法
6.测试:建立代理对象生产器,生产代理对象