反射:动态代理
interface接口一般都需要去实现自己的业务逻辑,实现类
不去主动编写接口的实现类,而是在服务启动的时候就创建这个接口的实列,就用到了jdk的动态代理
//接口
public interface Hello {
void morning(String name);
}
//实现类
public class HelloWorld implements Hello {
public void morning(String name) {
System.out.println("Good morning, " + name);
}
}
//创建实例,转型接口并调用,这种方式就是我们通常编写代码的方式。
Hello hello = new HelloWorld();
hello.morning("Bob");
还有一种方式是动态代码,我们仍然先定义了接口Hello
,但是我们并不去编写实现类,而是直接通过JDK提供的一个Proxy.newProxyInstance()
创建了一个Hello
接口对象。这种没有实现类但是在运行期动态创建了一个接口对象的方式,我们称为动态代码。JDK提供的动态创建接口对象的方式,就叫动态代理。
一个最简单的动态代理实现如下:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
InvocationHandler handler = new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method);
if (method.getName().equals("morning")) {
System.out.println("Good morning, " + args[0]);
}
return null;
}
};
Hello hello = (Hello) Proxy.newProxyInstance(
Hello.class.getClassLoader(), // 传入ClassLoader
new Class[]{Hello.class}, // 传入要实现的接口
handler); // 传入处理调用方法的InvocationHandler
hello.morning("Bob");
}
}
interface Hello {
void morning(String name);
}
在运行期动态创建一个interface
实例的方法如下:
-
定义一个
InvocationHandler
实例,它负责实现接口的方法调用; -
通过
Proxy.newProxyInstance()
创建interface
实例,它需要3个参数:- 使用的
ClassLoader
,通常就是接口类的ClassLoader
; - 需要实现的接口数组,至少需要传入一个接口进去;
- 用来处理接口方法调用的
InvocationHandler
实例。
- 使用的
-
将返回的
Object
强制转型为接口。
动态代理实际上是JVM在运行期动态创建class字节码并加载的过程,它并没有什么黑魔法,把上面的动态代理改写为静态实现类大概长这样:
public class HelloDynamicProxy implements Hello {
InvocationHandler handler;
public HelloDynamicProxy(InvocationHandler handler) {
this.handler = handler;
}
@Override
public void morning(String name) {
handler.invoke(
this,
Hello.class.getMethod("morning", String.class),
new Object[]{name});
}
}
其实就是JVM帮我们自动编写了一个上述类(不需要源码,可以直接生成字节码),并不存在可以直接实例化接口的黑魔法。
--这个是业务中的使用,业务中还是正常实现接口,但是我们也要知道java的动态代理是怎么回事
package com.cj.product;
import com.cj.product.dubbo.query.CjProductInfoExpandQueryService;
import com.cj.product.model.dto.CjPackAttrDTO;
import com.cj.product.model.dto.IdDTO;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.List;
/**
* @author
*/
@SpringBootApplication(scanBasePackages = "com.cj.product")
//@EnableDiscoveryClient
@EnableFeignClients(basePackages = {"com.cj.product.integration.feign", "com.cj.product.thirdparty.feign", "com.cj.supplier.feign"})
public class CjProductCenterServiceApplication {
public static void main(String[] args) {
SpringApplication.run(CjProductCenterServiceApplication.class, args);
InvocationHandler handler = (proxy, method, args1) -> {
System.out.println("开始了哦");
if (method.getName().equals("getPackAttr")) {
System.out.println("成功了");
}
return null;
};
CjProductInfoExpandQueryService o = (CjProductInfoExpandQueryService) Proxy.newProxyInstance(CjProductInfoExpandQueryService.class.getClassLoader(), new Class[]{CjProductInfoExpandQueryService.class},
handler);
IdDTO<String> idDTO = new IdDTO<>();
idDTO.setIds(Arrays.asList("00F8CD4B-7427-42AF-9068-399C79FEFD69"));
List<CjPackAttrDTO> packAttr = o.getPackAttr(idDTO);
System.out.println(packAttr);
}
}