JAVA 反射有对象反射和方法反射
主要用户解耦框架的研发,由于没有接触过框架的开发,因此不能理解对象反射和方法反射具体产生了什么样的作用
个人理解:对象反射和方法反射,不再是以前的new操作,以Person类举例
以前获取对象: Person person = new Person();
反射方式获取对象:Person object = (Person)Class.forName('Person').newInstance();
通常获取调用方法: person.sayHello("张三");
反射方式调用方法: Method method = object.getClass().getMethod("sayHello", String.class);
method.invoke(object, "张三");
看上去我们的调用更加不便捷,但是解耦的思想是:代码中取消固定的类的依赖,采用配置等方式解耦,一旦我们需要改动,即改动配置文件或少量配置即可,
而不用一个类里面大量修改new的对象,这个时候,反射就很好用了,他的类名等都是可以通过外部配置文件加载的,或者在Spring boot中通过注解进行
装配。
例举:
Properties pro=new Properties();
//获取class目录下的配置文件
pro.load(ReflectionText.class.getClassLoader().getResourceAsStream("application.properties"));
//获取配置文件定义的数据
String className=pro.getProperty("className");
String methodName=pro.getProperty("methodName");
//加载该类进内存
Class cls = Class.forName(className);
//执行方法
cls.getMethod(methodName).invoke(cls.newInstance());
------------------------------------------------------------------------------------------------------------------------------------------
动态代理模式的产生
如果仅仅是通过反射的方式使用类,我们会发现创建起来十分繁琐,且只能直接调用反射好的方法,我理解动态代理模式其实是反射的更加便捷的封装,
其有两大特点:
1.同样继承了反射的思想,是反射的更好的封装
2.可以在调用方法之前和方法之后处理自己的逻辑,例如:基于一个特别的规则,方法就不会被调用了,而这部分逻辑不需要在类里面实现,
是通过先于类调用做到了拦截,这也产生了后面拦截器的用法。
动态代理的思想是:创建一个代理对象,该对象和实际对象是映射的,用户在使用的时候,通过代理对象调用实际对象的方法,
同时,代理对象也可以在自己内部做逻辑处理
动态代理模式有两种:
1.JDK模式
JDK代理模式要求必须提供接口才能使用
JDK动态代理实现:
(1).创建一个实际的类(产生实际对象使用)
创建接口:
cat HelloWorld.java
package reflect.jdk;
public interface HelloWorld {
public void sayHello();
}
实现接口:
cat HelloWorldImpl.java
package reflect.jdk;
public class HelloWorldImpl implements HelloWorld{
@Override
public void sayHello() {
System.out.println("Hello World");
}
}
(2)实现动态代理
package reflect.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxyExample implements InvocationHandler {
//真实对象
private Object target = null;
//代理对象
public Object bind(Object target){
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
//代理的方法逻辑
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入代理方法逻辑");
System.out.println("在调度真实对象之前的服务");
Object obj=method.invoke(target, args);
System.out.println("在调度真实对象之后的服务");
return obj;
}
}
(3)测试
package reflect.jdk;
public class TestJdkProxy {
public static void main(String args[]){
JdkProxyExample jdkProxyExample = new JdkProxyExample();
HelloWorld proxy = (HelloWorld) jdkProxyExample.bind(new HelloWorldImpl());
proxy.sayHello();
proxy.sayHello2();
HelloWorld a = new HelloWorldImpl();
a.sayHello();
}
}
2.GCLiB模式
GCLIB则在没有提供接口的情况下使用,需要提供一个非虚拟类
1.创建非虚拟类
cat HelloWorldImpl.java
package reflect.jdk;
public class HelloWorldImpl implements HelloWorld{
@Override
public void sayHello() {
System.out.println("Hello World");
}
}
(2)实现代理
package reflect.cglib;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyExample implements MethodInterceptor {
//生成代理对象
public Object getProxy(Class cls){
//CGLIB enhancer 增强类对象
Enhancer enhancer = new Enhancer();
//设置增强类型
enhancer.setSuperclass(cls);
//定义代理逻辑对象为当前的对象,要求当前对象实现MethodInterceptor的方法
enhancer.setCallback(this);
//生成并返回代理对象
return enhancer.create();
}
//代理逻辑方法
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("调用真实对象前");
Object result = methodProxy.invokeSuper(o,objects );
System.out.println("调用真实对象后");
return result;
}
}
(3)测试
package reflect.cglib;
import reflect.jdk.HelloWorld;
import reflect.jdk.HelloWorldImpl;
public class TestCglibProxy {
public static void main(String args[]){
CglibProxyExample cglibProxyExample = new CglibProxyExample();
HelloWorldImpl helloWorld = (HelloWorldImpl) cglibProxyExample.getProxy(HelloWorldImpl.class);
helloWorld.sayHello();
}
}
两种方式的使用都是一样的流程,对象->代理对象->代理逻辑方法
不同的是,jdk的是一定要先有个对象,为了该对象能够泛化使用,才有了接口
而cglib是直接传入类,由他自己创建对象,最后仍然是走到逻辑对象和代理逻辑方法上
而代理方法其实就是之前的method.invoke 的功能