反射就是在运行时才知道要操作的类是什么,并且可以在运行时获取类的完整构造,并调用对应的方法。
JDK的java.lang.reflect包提供了反射支持。

1.Class类

程序运行期间,Java会给每个对象都维护一个运行时类型标识。该对象保存着该类的信息。

三种获取Class类的方法

  • object.getClass()
  • Class.forName(类的全路径名)
  • Employee.class

2.反射

java.lang.reflect包下有三个类Field、Method、Constructor分别描述了域、方法、构造器。可以获取类的所有信息。
Class类的getFields、getMethods、getConstructors方法会返回响应的的信息。

两个简单例子

下面实现了两个相同的操作,不同的是在反射中我们可以事先没有得到该类,通过反射的方法去new 实例,并调用方法。

3.动态代理

代理类在程序运行时完成创建的代理方式被成为动态代理。

动态代理相对于静态代理来说,耦合性更低。像静态代理如果需要代理100个接口,就得写100个代理类,而动态代理只需要一个。

3.1 JDK动态代理

接口以及被代理对象

public interface House {
    void sell();
}

public class Bieshu implements House{
    @Override
    public void sell() {
        System.out.println("卖了大别墅~");
    }
}

InvocationHandler

public class HouseHandler implements InvocationHandler {
    private Object obj;


    public HouseHandler(Object obj){
        super();
        this.obj = obj;
    }


    @Override
    public Object invoke(Object proxy, Method method, Object[] objects) throws Throwable {
        System.out.println("出售前~");
        method.invoke(obj);
        System.out.println("出售后~");
        return null;
    }
}

main方法

public static void main(String[] args) {
        Bieshu bieshu = new Bieshu();
        HouseHandler houseHandler = new HouseHandler(bieshu);
        Class<?> bieshuClass = bieshu.getClass();
        House proxyInstance = (House) Proxy.newProxyInstance(bieshuClass.getClassLoader(), bieshuClass.getInterfaces(), houseHandler);
        proxyInstance.sell();
    }


--------------------------------
出售前~
卖了大别墅~
出售后~

所以总的来说JDK代理就是两层代理,Proxy代理了InvocationHandler,而InvocationHandler代理了被代理类。

3.2 CGLib代理

代理的目的是构造一个和被代理对象有相同行为的对象,所以不一定需要通过持有的方式来实现,也可以通过继承,并重写父类方法来实现。CGLib就是如此。

被代理类

public class HelloService {

    public HelloService() {
        System.out.println("HelloService构造");
    }

    /**
     * 该方法不能被子类覆盖,Cglib是无法代理final修饰的方法的
     */
    final public String sayOthers(String name) {
        System.out.println("HelloService:sayOthers>>" + name);
        return null;
    }

    public void sayHello() {
        System.out.println("HelloService:sayHello");
    }
}

MethodInterceptor

public class CglibProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable {
        // 这里增强
        System.out.println("收钱");

        return arg3.invokeSuper(arg0, arg2);
    }

}

main

public static void main(String[] args) {
        // 通过CGLIB动态代理获取代理对象的过程
        Enhancer enhancer = new Enhancer();
        // 设置enhancer对象的父类
        enhancer.setSuperclass(HelloService.class);
        // 设置enhancer的回调对象
        enhancer.setCallback(new MyMethodInterceptor());
        // 创建代理对象
        HelloService proxy= (HelloService)enhancer.create();
        // 通过代理对象调用目标方法
        proxy.sayHello();
    }

3.3 两者的区别

  • JDK动态代理是面向接口的
  • CGLib动态代理是通过字节码底层继承来实现的。
  • spring中当被代理类是实现类就会使用JDK代理,否则则用CGLib
  • CGLib创建动态代理对象在运行中比JDK代理的快很多,所以使用单例时比较适合。
  • CGLib创建动态代理对象在创建中比JDK代理的慢很多
  • 目前随着JDK的版本提高,JDK动态代理的效率已经比CGLib高了。
public class ReflectTest {
    public static class BasketBall{
        private int price;

        public int getPrice() {
            return price;
        }
        public void setPrice(int price) {
            this.price = price;
        }
    }

    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
        // 1.正常调用
        BasketBall basketBall = new BasketBall();
        basketBall.setPrice(10);

        // 2.反射调用
        System.out.println(basketBall.getClass().getName());
        String name = "reflect.ReflectTest$BasketBall";
        Class classBasketBall = Class.forName(name);
        Method method = classBasketBall.getMethod("setPrice", int.class);
        Constructor constructor = classBasketBall.getConstructor();
        Object instance = constructor.newInstance();
        method.invoke(instance,10);
        
    }
}

3.4 AOP

AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。在OOP中允许定义从上到下的关系,但是对横向关系就无能为力了,AOP就提供了横向的处理能力。比如说日志,权限校验等功能会横切在代码中,这会导致代码不能复用。

spring 通过动态代理实现了AOP。