一、反射
反射在之前的文章中详细的解释过了,简单概括就是:可以动态的获取到一个类内部的所有的信息,动态的去创建对象和使用对象以及可以操作对象的属性和方法。
二、代理
首先解释一下代理:使用一个代理对象将对象包装起来,然后用该代理对象来取代该对象,任何对原始对象的调用都要通过代理,代理对象决定是否以及何时调用原始对象的方法。
三、静态代理
静态代理:被代理对象和代理对象要实现同一套接口且代理对象内部要包含被代理对象,被代理对象覆盖重写接口方法,在方法内部加上实际业务上的增强。
代码目录
代码演示
//公共接口 public interface ZhangSanInterface { //定义一个吃饭的抽象方法 void eat(); } //张三类 public class ZhangSan implements ZhangSanInterface { @Override public void eat() { System.out.println("吃饭。。。"); //实现方法体 } } //张三代理类 public class ZhangSanProxy implements ZhangSanInterface{ private ZhangSanInterface zhangSanInterface; public ZhangSanProxy(ZhangSanInterface zhangSanInterface) { this.zhangSanInterface = zhangSanInterface; } @Override public void eat() { System.out.println("饭前洗手。。"); //方法前增强 zhangSanInterface.eat(); System.out.println("饭后洗碗。。"); //方法后增强 } } //测试类 public class Main01 { public static void main(String[] args) { ZhangSanProxy proxy = new ZhangSanProxy(new ZhangSan()); //代理对象中传入张三对象 proxy.eat(); } }
总结:静态代理不需要使用反射机制就能够实现,但是也存在了很明显的缺陷,如果想要在加一些其他的被代理类,必须要修改代码,不符合开闭原则(对外扩展开放,对内修改关闭),扩展性差、维护性差。
四、动态代理
动态代理:在程序的执行时(动态),使用jdk的反射机制,创建对象的能力,创建的是代理类的对象,而不用我们自己创建类文件。
1、JDK动态代理
使用java反射包中的类和接口实现动态代理的功能。 反射包 java.lang.reflect,里面有三个类:InvocationHandler、Method、Proxy
1) InvocationHandler接口(调用处理器) :就-一个方法invoke ( )
invoke():表示代理对象要执行的功能代码。你的代理类要完成的功能就写在invoke ()方法中。
代理类完成的功能:
1.调用目标方法,执行目标方法的功能
2.功能增强,在目标方法调用时,增加功能。
方法原型:
参数: object proxy :jdk创建的代理对象,无需赋值。
Method method: 目标类中的方法,jdk提供me thod对象的
object[] args: 目 标类中方法的参数,jdk提供的 。
public object invoke (object proxy, Method method, Object[] args)
InvocationHandler接口:表示你的代理要千什么。
怎么用: 1.创建类实现接口Invocati onHandler
2.重写invoke()方法,把原来静态代理中代理类要完成的功能,写在这。
2) Method类:表示方法的,确切 的说就是目标类中的方法.
作用:邇过Method可以执行某个目标类的方法,Method. invoke() ;
method. invoke(目标对象,方法的参数)
3) Proxy类: 核心的对象,创建代理对象。之前创建对象都是new类的构造方法(),现在我们是使用Proxy类的方法,代替new的使用。
方法:静态方法 newProxyInstance ()
作用是:创建代理对象, 等同于静态代理中的 代理类 proxy = new 代理类() ;
参数:
1. ClassLoader loader 类加载器,负责向内存中加载对象的。使用反射获取对象的ClassLoader类a,a. getCalss () .getClassLoader(),目标对象的类加载器。
2. Class>[] interfaces:接口,目标对象实现的接口,也是反射获取的。
3. InvocationHandler h :我们自己写的,代理类要完成的功能。
返回值:newProxyInstance () 的返回值就是代理对象。
实现动态代理的步骤
1.创建接口,定义目标类要完成的功能
2.创建目标类实现接口
3.创建InvocationHandler接口的实现类,在invoke方法中完成代理类的功能
1.调用目标方法
2.增强功能
4.使用Proxy类的静态方法,创建代理对象。并把返回值转为接口类型。
代码目录
代码展示
//目标接口 public interface Target { void eat(); } //目标类 public class TargetImpl implements Target { @Override public void eat() { System.out.println("吃饭饭。。"); } } //必须实现InvocationHandler接口,完成动态代理要做的功能(1.调用目标方法 2.功能增强) public class MyHandler implements InvocationHandler { private Object taget; public MyHandler(Object taget) { this.taget = taget; } //动态代理:对象是活动的,不是固定的,需要传进来 //传入是谁,就给谁创建代理。 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("洗手手。。"); Object invoke = method.invoke(taget, args);//执行目标方法 System.out.println("洗碗碗。。"); return null; } } //主函数 public class Main02 { public static void main(String[] args) { //1、创建目标对象 Target taget = new TargetImpl(); //2、创建InvocationHandler对象 InvocationHandler handler = new MyHandler(taget); //3、创建代理对象 Target proxy = (Target) Proxy.newProxyInstance( taget.getClass().getClassLoader(), taget.getClass().getInterfaces(), handler); //4、通过代理执行方法 proxy.eat(); } }
2、CGLIB动态代理
cglib是第三方的工具类,创建代理对象。cglib原理是继承,通过继承目标类,创建它的子类,在子类中重写重写父类中同名的方法,实现功能修改/增强。cglib动态代理要求目标类能够被继承。
目录展示
代码展示
//目标类 public class Target { public void eat(){ System.out.println("吃饭饭。。"); } } //实现MethodInterceptor接口 public class CglibProxy implements MethodInterceptor { private Object target; public CglibProxy(Object target) { this.target = target; } /** * @param proxy 代理对象引用 * @param method 被代理对象的方法的描述引用 * @param objects 方法的参数 * @param methodProxy 代理对象的 对目标对象的方法的描述 * @return * @throws Throwable */ @Override public Object intercept(Object proxy, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("洗手手。。"); method.invoke(target,objects); System.out.println("洗碗碗。。"); return null; } } /主方法测试 public class Main03 { public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(new Target()); Target target = (Target) Enhancer.create(Target.class, cglibProxy); target.eat(); } }