Java反射与代理(静态代理,动态代理(jdk动态代理和CGLIB动态代理))

反射与动态代理

反射

反射,即通过类对象class来操作数据。

获取类对象class

 //全类名获取
Class clazz1 = Class.forName("com.example.reflection.Student");

//根据类+.class
Class clazz2 = Student.class;

//通过实例对象getClass方法
Student student = new Student("小明",1);
Class clazz3 = student.getClass();

//根据构造器获取
ClassLoader classLoader = clazz1.getClassLoader();
Class clazz4 = classLoader.loadClass("com.example.reflection.Student");

获取类的元素Field

getFiled - 根据名称获取公有的(public)类成员。
getDeclaredField - 根据名称获取已声明的类成员。但不能得到其父类的类成员。
getFields - 获取所有公有的(public)类成员。
getDeclaredFields - 获取所有已声明的类成员。

获取类的方法Method

getMethod - 返回类或接口的特定方法。其中第一个参数为方法名称,后面的参数为方法参数对应 Class 的对象(如参数是String类型就填String.class以此类推)。
getDeclaredMethod - 返回类或接口的特定声明方法。其中第一个参数为方法名称,后面的参数为方法参数对应 Class 的对象。
getMethods - 返回类或接口的所有 public 方法,包括其父类的 public 方法。
getDeclaredMethods - 返回类或接口声明的所有方法,包括 public、protected、默认(包)访问和 private 方法,但不包括继承的方法。
调用的话,使用method.invoke(参数)。

获取类的构造器Constructor

getConstructor - 返回类的特定 public 构造方法。参数为方法参数 对应 Class 的对象。
getDeclaredConstructor - 返回类的特定构造方法。参数为方法参数 对应 Class 的对象。
getConstructors - 返回类的所有 public 构造方法。
getDeclaredConstructors - 返回类的所有构造方法。

以上都是反射的入门,下面是反射的用处:代理。

静态代理

新建一个接口UserService

public interface UserService {

    public void select();
    public void update();

}

写一个实现类UserServiceImpl

public class UserServiceImpl implements UserService {
    @Override
    public void select() {
        System.out.println("查询方法");
    }

    @Override
    public void update() {
        System.out.println("更新方法");
    }
}

再写一个静态代理类

/**
 * 静态代理
 * 以某个实现类作为成员变量,对它的操作进行增强
 * 缺点:
 * 虽然静态代理实现简单,且不侵入原代码,但是,当场景稍微复杂一些的时候,静态代理的缺点也会暴露出来。
 * 1.当需要代理多个类的时候,由于代理对象要实现与目标对象一致的接口,有两种方式:
 * 1.1 只维护一个代理类,由这个代理类实现多个接口,但是这样就导致代理类过于庞大
 * 1.2 新建多个代理类,每个目标对象对应一个代理类,但是这样会产生过多的代理类
 * 2.当接口需要增加、删除、修改方法的时候,目标对象与代理类都要同时修改,不易维护。
 */
public class UserServiceProxy implements UserService{

    //被代理的对象
    private UserService target;

    public UserServiceProxy(UserService target){
        this.target = target;
    }

    @Override
    public void select() {
        preHandle();
        target.select();
        afterHandle();
    }

    @Override
    public void update() {
        preHandle();
        target.update();
        afterHandle();
    }

    private void preHandle(){
        System.out.println("前置处理");
    }

    private void afterHandle(){
        System.out.println("后置处理");
    }

    public static void main(String[] args) {
        UserServiceImpl userService = new UserServiceImpl();
        UserServiceProxy proxy = new UserServiceProxy(userService);

        proxy.select();
        proxy.update();
    }

}

动态代理

代理类通过继承InvocationHandler接口,重写invoke方法。

使用的时候三个步骤:

  1. 先要弄一个接口实现类实例出来。
  2. 再弄个代理类实例。
  3. 通过Proxy.newInstance()方法弄个proxy出来。
/**
 * jdk的动态代理
 */
public class UserServiceDynamicProxy implements InvocationHandler {

    //被代理的对象,这个其实可以不写,只是习惯。
    private Object target;

    public UserServiceDynamicProxy(Object target){
        this.target=target;
    }

    //proxy,代理对象本身,method 代理的方法,args 方法参数
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        //前置处理
        preHandle();
        Object result = method.invoke(target,args);
        //后置处理
        afterHandle();
        return result;
    }


    private void preHandle(){
        System.out.println("前置处理");
    }

    private void afterHandle(){
        System.out.println("后置处理");
    }


    public static void main(String[] args) {

        //被代理对象
        UserService target = new UserServiceImpl();

        //代理对象实现类实例
        UserServiceDynamicProxy handler = new UserServiceDynamicProxy(target);
        
        
        UserService proxy = (UserService) Proxy.newProxyInstance(
                UserService.class.getClassLoader(),//接口的类加载器
                UserService.class.getInterfaces(),//实现的接口
                handler// 代理对象实现类实例
        );
        //调用方法
        proxy.select();
        proxy.update();
    }
}

以上是jdk的动态代理,原理是基于接口的反射,意味着类不继承接口就用不了jdk的动态代理,所以衍生出CGLIB代理,代理类通过继承接口实现类。

CGLIB动态代理

第一步:导依赖

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

下面举个例子,Student类

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {

    private String name;

    private Integer score;
    
    public void work(){
        System.out.println("作业还没写完");
    }

}

CGLIB代理类,需要实现 MethodInterceptor接口

public class StudentProxy implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        preHandle();
        Object res = methodProxy.invokeSuper(obj, args);
        afterHandle();
        return res;
    }

    private void preHandle()
    {
        System.out.println("作业借我抄下");
    }

    private void afterHandle()
    {
        System.out.println("写完再借我抄下");
    }

    public static void main(String[] args) {
        //使用
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Student.class);   //将代理类作为父类
        enhancer.setCallback(new StudentProxy());

        Student proxy = (Student) enhancer.create();
        proxy.work();
    }
}

使用CGLIB代理类:通过Enhancer类的setSuperclass方法和setCallback方法初始化后,create出来的就是代理类实例了。

posted @ 2024-06-14 15:29  Liang2003  阅读(1)  评论(0编辑  收藏  举报