1、java反射技术
//【java.lang.reflect.*】 反射专用包 // 反射:只要配置就能生成对象,解除程序耦合度,灵活,缺点是运行慢 ReflectServiceImple1 obj1 = (ReflectServiceImple1)Class.forName("com.alison.ssm.ReflectServiceImple1").newInstance(); //无参构造 ReflectServiceImple2 obj = (ReflectServiceImple2)Class.forName("com.alison.ssm.ReflectServiceImple2").getConstructor(String.class).newInstance("张三"); //有参构造 // Class.forName()就是给类加载器注册一个全限定名,并使用newInstance()实例化对象 // 反射方法 Method method = ReflectServiceImple1.class.getMethod("sayHello", String.class); // 先获得Class对象,再使用getMethod方法 得到Method实例 Object retObj = method.invoke(new ReflectServiceImple1(), "alison"); // 使用invoke激活方法,获得返回值,传入类实例和方法参数 // 也可以这样实现: new ReflectServiceImple1().getClass().getMethod("sayHello", String.class) // 【注意】一定用try..catch结构包裹,因为容易爆ClassNotFound或者IllegalAccess等的异常
2、动态代理
动态代理的意义在于生成一个占位,又称代理对象,来代理真实对象,从而控制真实对象访问
java中最常用的代理方式有 JDK, CGLIB, javassist, ASM等,常见前两种
主要有两个步骤:
1)代理对象与真实对象建立联系,生成代理对象
2)实现代理对象的代理逻辑方法
2.1 JDK动态代理
使用JDK动态代理,需要实现java.lang.reflect.InovationHandler接口,实现invoke 方法
// 真实操作类 public interface HelloWorld{ public void sayHelloWorld(); } public class HelloWorldImp implements HelloWorld{ @override public void sayHelloWorld(){ System.out.println("Hello World!"); } } //【JDK动态代理】 // 需要实现java.lang.reflect.InvicationHandler接口,invoke()方法,且被代理类 必须有实现的接口!! 如 HelloWorldImp implements HelloWorld public class JDKProxyExample implements InvicationHandler { private Object target; /** * 建立代理关系,返回代理对象 * @param target 真实对象 * @return 代理对象 */ public Object bind(Object target){ this.target = target; // 三个参数:真实类加载器,接口数组,当前代理类 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); } /** * 代理逻辑方法:当使用代理对象调用某方法时,就会自动调用invoke方法 * @param proxy 代理对象 * @param method 当前调度方法 * @param args 当前方法参数 * @return 代理结果返回 * @throws Trowable 异常 */ @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; } }
实现InvicationHandler 接口,主要有两个方法,bind用于和真实对象建立联系,返回代理对象,内部具体调用的是Proxy.newProxyInstance()方法,传入三个参数:类加载器,类接口(表示生成的动态代理对象挂在哪些接口下),当前类对象(必须实现invoke方法)
invoke方法就是可以启动被代理对象的真实方法了,可以加入自己的逻辑,使用的就是方法反射;当使用代理对象调用某方法时,就会自动调用invoke方法
测试:
public void testJDKProxy(){ JDKProxyExample jdk = new JDKProxyExample(); HelloWorld proxy = (HelloWorld)jdk.bind(new HelloWorldImp()); // 此处需要强转下 proxy.sayHelloWorld(); // 代理对象调用方法,会进入到代理类的invoke()方法中处理该方法 }
输出:
进入代理逻辑方法
在调用真实对象前的服务操作
Hello World!
在调用真实对象后的服务操作
2.2 CGLIB动态代理
JDK代理必须提供接口,针对无接口实现的类,可以使用CGLIB
//【CGLIB动态代理】 // 优势:不要求被代理类 必须实现某接口 public class CglibProxyExample implements MethodInterceptor { /** * 生成CGLIB代理对象 * @param cls ——Class类 * @return Class类的CGLIB代理对象 */ public void getProxy(Class cls){ //CGLIB enhancer增强类对象 Enhancer enhancer = new Enhancer(); // 设置增强类型 enhancer.setSuperclass(cls); // 定义代理逻辑对象为当前对象,要求当前对象实现MethodInteceptor犯法 enhancer.setCallback(this); // 生成并返回代理对象 return enhancer.create(); } /** * 代理逻辑方法 * @param methodProxy 方法代理 * .. */ @override public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { System.err.println("在调用真实对象前的服务操作"); //CGLIB反射调用真实对象方法 Object result = methodProxy.invokeSuper(proxy, args); System.err.println("在调用真实对象hou的服务操作"); return result; } public void testCglibProxy(){ CglibProxyExample cpe = new CglibProxyExample(); ReflectServiceImple1 obj = (ReflectServiceImple1)cpe.getProxy(ReflectServiceImple1.class); obj.sayHello("张三"); } }
本质上是调用了 Enhancer 类,基于父类进行生成代理对象