回顾Java反射知识

因为动态代理需要用到,所以我们要先学习Java的反射知识。

Java反射中有Method类
Method类,表示方法类中的方法,通过Method可以执行某个类中的某个方法

回顾反射知识咋用

1 先创建一个接口

package com.test;

public interface HelloService {
   
    // 根据name打招呼
    public void sayHello(String name);
}

2 创建一个类实现这个接口

package com.test;
// HelloService接口的实现类
public class HelloServiceImpl implements HelloService {
   
    @Override
    public void sayHello(String name) {
   
        System.out.println("您好"+name);
    }
}

3 测试,执行HelloServiceImpl这个类里面的方法

package com.test;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

// 测试
public class TestHelloService {
   
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
   


// 正常的通过对象调用sayHello方法
创建这个类的对象后执行这个方法,是最普遍的方法
        HelloService helloService = new HelloServiceImpl();
        System.out.println("通过对象调用sayHello方法");
        helloService.sayHello("张三");




通过反射,咋执行这个方法
// 通过反射机制执行sayHello方法,核心Method(类中的方法)
        // 创建需要调用sayHello的对象
        HelloService Service = new HelloServiceImpl();
        // 获取sayHello名称对应的Method类对象
        // method代表的是sayHello这个方法
        /* 参数: 1.需要执行的方法名 2.参数的类型 */
        Method method = HelloService.class.getMethod("sayHello", String.class);
        
        // 通过Method可以执行sayHello方法的调用
        /* invoke是Method类中的一个方法,表示执行方法的调用 参数: 1.Object:表示对象,就是要执行这个对象的sayHello方法 2.Object...args:方法执行时的参数值 返回值:Object,表示返回执行后的返回值,sayHello返回是void */
        // 表示执行Service对象的sayHello返回参数是李四
        System.out.println("通过反射调用sayHello方法");
        Object object = method.invoke(Service,"李四");
    }
}

动态代理

什么叫动态代理

不用自己手动的去创建代理类。
我们自己的一个类,可以创建很多的对象,现在想要在这么多对象上,都要创建代理类。意思是每一个对象都需要创建代理类,我们就可以动态的实现
jdk动态代理,实际类和代理类一定要实现同一个接口,这个必须记住

jdk的动态代理:

jdk动态代理使用到
反射包java.lang.reflect
,里面包含3个类InvocationHandler、Method、Proxy
InvocationHandler接口(调用处理器):Invoke()方法,(需要执行的功能,我的理解:原来的方法和扩展的方法

实现步骤

1 写一个接口,这个接口是实际类和代理类都需要实现的。jdk动态代理就是实际类和代理类都要实现同一个接口,重写里面的 方法,这个是必须的

我们先写一个接口

package com.service;
// 目标类实现的方法
public interface UsbSell {
   
    public float sell(int amount);
}

2 写一个实际类,实现这个接口,重写里面的方法

这个类就是实际类,我们要对这个里面的方法功能实现扩展。

package com.factory;

import com.service.UsbSell;
// 目标类
public class UsbKingFactory implements UsbSell {
   
    // 目标方法
    @Override
    public float sell(int amount) {
   
        System.out.println("执行目标类方法sell");
        return 85.0f;
    }
}

3 创建InvocationHandler接口的实现类
这个是必须的,相当于这个类里面就是写功能扩展的方法。相当于aop,
里面不仅有原来的方法,还有功能扩展的方法

package com.handler;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
// 必须实现InvocationHandler接口,完成代理功能(1.调用目标方法,2.功能增强)
// 负责执行目标类的方法
// 我的理解:只是执行了目标类的方法和代理类的功能增强,返回目标类方法的返回值给InvocationHandler对象
public class MySellHandle implements InvocationHandler {
   
    private Object target = null;
    // 动态代理:目标对象是活动的,不是固定的,需要传进来
    // 传入是哪个对象,就给哪个对象创建代理
    public MySellHandle(Object target){
   
        // 给目标对象赋值
        this.target = target;
    }
    @Override
    public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
   
        Object res = null;
        
         //在代理真实对象前我们可以添加一些自己的操作
        System.out.println("在调用之前,我要干点啥呢?");
 
        System.out.println("Method:" + method);
 
        //当代理对象调用真实对象的方法时,其会自动的跳转到代理对象关联的handler对象的invoke方法来进行调用
        Object returnValue = method.invoke(target , objects);
 
        //在代理真实对象后我们也可以添加一些自己的操作
        System.out.println("在调用之后,我要干点啥呢?");
 
        return returnValue;
    }
}

4 创建测试类,使用Proxy类的静态方法newProxyInstance,创建代理对象


 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
 
/** * 动态代理演示 */
public class DynamicProxyDemonstration
{
   
    public static void main(String[] args)
    {
   
        //代理的真实对象
        Subject realSubject = new RealSubject();
        
        /** * InvocationHandlerImpl 实现了 InvocationHandler 接口,并能实现方法调用从代理类到委托类的分派转发 * 其内部通常包含指向委托类实例的引用,用于真正执行分派转发过来的方法调用. * 即:要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法 */
        InvocationHandler handler = new InvocationHandlerImpl(realSubject);
 
        ClassLoader loader = realSubject.getClass().getClassLoader();
        Class[] interfaces = realSubject.getClass().getInterfaces();
        /** * 该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例 */
        Subject subject = (Subject) Proxy.newProxyInstance(loader, interfaces, handler);
 
        System.out.println("动态代理对象的类型:"+subject.getClass().getName());
 
        String hello = subject.SayHello("ttt");
        System.out.println(hello);
// String goodbye = subject.SayGoodBye();
// System.out.println(goodbye);
    }
 
}

注意

注意的是在使用jdk动态代理时目标类一个要实现实现功能接口。

动态代理相当于就是实现 功能的扩展