Java工程师知识树 / Java基础
反射常见应用场景
- 反射实现驱动加载
- 反射实现配置文件加载
- 反射实现工厂模式
- 反射实现静态代理
- 反射实现动态代理
反射实现驱动加载
public static void main(String[] args) throws Exception {
// 注册 JDBC 驱动
// 把Driver类装载进JVM
Class.forName("com.mysql.cj.jdbc.Driver");
try (
Connection conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/myData", "root", "");
Statement stmt = conn.createStatement();
) {
// 打开链接
System.out.println("连接数据库...");
// 执行查询
System.out.println(" 实例化Statement对...");
String sql = "SELECT * FROM xtb";
ResultSet rs = stmt.executeQuery(sql);
while (rs.next()) {
// 通过字段检索
int id = rs.getInt("user_id");
String name = rs.getString("user_name");
// 输出数据
System.out.print("ID: " + id);
System.out.print(", 名字: " + name);
System.out.print("\n");
}
// 完成后关闭
rs.close();
} catch (Exception e) {
// 处理 Class.forName 错误
e.printStackTrace();
}
System.out.println("jdbc_test_end!");
}
反射实现配置文件加载
import java.io.FileReader;
import java.io.IOException;
import java.lang.reflect.Method;
import java.util.Properties;
/*
* 我们利用反射和配置文件,可以使:应用程序更新时,对源码无需进行任何修改
* 我们只需要将新类发送给客户端,并修改配置文件即可
* dto.txt内容:
className = com.wechat.management.reflection.TestInvoke
methodName = invokeMethod
*/
public class Demo {
public static void main(String[] args) throws Exception {
//1.通过反射获取Class对象
Class stuClass = Class.forName(getValue("className"));//"com.wechat.management.reflection.TestInvoke"
//2.获取invokeMethod()方法
Method method = stuClass.getMethod(getValue("methodName"));//invokeMethod
//3.创建对象
TestInvoke testInvoke = (TestInvoke) stuClass.newInstance();
//3.调用invokeMethod()方法
String retrunStr = (String) method.invoke(testInvoke, null);
System.out.println("获取方法执行后的返回值:"+retrunStr);
}
//此方法接收一个key,在配置文件中获取相应的value
public static String getValue(String key) throws IOException{
Properties pro = new Properties();//获取配置文件的对象
FileReader in = new FileReader("E:\\projects\\management\\src\\main\\resources\\dto.txt");//获取输入流
pro.load(in);//将流加载到配置文件对象中
in.close();
return pro.getProperty(key);//返回根据key获取的value值
}
}
反射实现工厂模式
//动物接口
interface Animal {
public void speak();
}
//人实现类
class Man implements Animal {
@Override
public void speak() {
System.out.println("是人会说话:哈哈哈!!!");
}
}
//狗实现类
class Dog implements Animal {
@Override
public void speak() {
System.out.println("是狗不会说话:汪汪汪!!!");
}
}
//工厂类,多个对象都实现了相同的接口,工厂模式是把这些对象做一个整合,可以通过工厂类获取指定的对象
class Factory {
/**
* 采用反射机制的简单工厂模式,即使增加动物接口的实现也不用改该工厂类的方法
*/
public Object getAnimal(String className) throws Exception {
Class> cls = Class.forName(className);
return cls.newInstance();
}
/**
* 简单工厂模式,增加动物接口的实现就要在该方法中做兼容处理
*/
public Object getAnimalByType(String type) {
if("com.wechat.management.reflection.Man".equals(type)){
return new Man();
}
if("com.wechat.management.reflection.Dog".equals(type)){
return new Dog();
}
return null;
}
}
//测试类
public class ReflectFactory {
public static void main(String[] args) throws Exception {
Factory factory = new Factory();
Animal man = (Animal) factory.getAnimal("com.wechat.management.reflection.Man");
man.speak();
Animal dog = (Animal) factory.getAnimalByType("com.wechat.management.reflection.Dog");
dog.speak();
}
}
执行结果:
是人会说话:哈哈哈!!!
是狗不会说话:汪汪汪!!!
反射实现静态代理
静态代理模式与简单工厂模式的区别
package com.wechat.management.reflection;
//动物接口
interface Animal {
public void speak();
}
//人实现类
class Man implements Animal {
@Override
public void speak() {
System.out.println("是人会说话:哈哈哈!!!");
}
}
//狗实现类
class Dog implements Animal {
@Override
public void speak() {
System.out.println("是狗不会说话:汪汪汪!!!");
}
}
//工厂类,多个对象都实现了相同的接口,工厂模式是把这些对象做一个整合,可以通过工厂类获取指定的对象
class Factory {
/**
* 采用反射机制的简单工厂模式
*/
public Object getAnimal(String className) throws Exception {
Class> cls = Class.forName(className);
return cls.newInstance();
}
/**
* 简单工厂模式
*/
public Object getAnimalByType(String type) {
if("com.wechat.management.reflection.Man".equals(type)){
return new Man();
}
if("com.wechat.management.reflection.Dog".equals(type)){
return new Dog();
}
return null;
}
}
//动物代理类,代理类与被代理对象实现相同的接口,代理模式只是隐藏某个对象的行为
class AnimalProxg implements Animal{
//内部指定是哪个被代理的对象
private Animal animalProxg;
public AnimalProxg() {
animalProxg = new Dog();//默认是条狗;外部调用AnimalProxg不知道它是Dog对象
}
//代理里使用工厂
public AnimalProxg(String className) {
try {
Factory factory = new Factory();
this.animalProxg = (Animal) factory.getAnimal(className);;//当狗or当人由外部决定
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void speak() {
animalProxg.speak();//说话了
}
}
//测试类
public class ReflectFactory {
public static void main(String[] args) throws Exception {
//----------工厂模式-------------
System.out.println("----------工厂模式-------------");
Factory factory = new Factory();
Animal man = (Animal) factory.getAnimal("com.wechat.management.reflection.Man");
man.speak();
Animal dog = (Animal) factory.getAnimalByType("com.wechat.management.reflection.Dog");
dog.speak();
//----------代理模式-------------
System.out.println("----------代理模式-------------");
//使用默认值,即默认是条狗
AnimalProxg animalProxg = new AnimalProxg();
animalProxg.speak();
//----------代理+工厂-------------
System.out.println("----------代理+工厂-------------");
//把它当成人了
AnimalProxg animalProxg2 = new AnimalProxg("com.wechat.management.reflection.Man");
animalProxg2.speak();
}
}
执行结果:
----------工厂模式-------------
是人会说话:哈哈哈!!!
是狗不会说话:汪汪汪!!!
----------代理模式-------------
是狗不会说话:汪汪汪!!!
----------代理+工厂-------------
是人会说话:哈哈哈!!!
反射实现动态代理
动态代理步骤:
- 创建一个要调用的接口实现,获取接口实现的Class。
- 实现
InvocationHandler
接口并重写invoke方法,实例化InvocationHandler
对象,用来处理Proxy
的方法调用。 - 通过
Proxy.newProxyInstance(classLoader, interfaces, proxyHandler);
实例化一个proxy
对象。
1.实现InvocationHandler接口并重写invoke方法:
每一个动态代理类都必须要实现 InvocationHandler
这个接口,并且每个代理类的实例都关联到了一个 Handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由 InvocationHandler
这个接口的 invoke
方法来进行调用。
为什么动态代理必须实现 InvocationHandler
这个接口呢?是因为可以通过实现 InvocationHandler
这个接口来规范动态代理调用方法时的规范。
/**
* proxy - 代理的真实对象。具体是接口的一个实现。
* method - 所要调用真实对象的某个方法的 Method 对象
* args - 所要调用真实对象某个方法时接受的参数
*/
public interface InvocationHandler {
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable;
}
实例化一个 proxy 对象:
//返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序InvocationHandler
public static Object newProxyInstance(ClassLoader loader, Class>[] interfaces,InvocationHandler invocationHandler)
Proxy.newProxyInstance(classLoader, interfaces, proxyHandler);
三个参数分别是什么作用
classLoader:类加载器,我们手动写的都是java文件,需要编译成class文件,这个是遵循JVM规范的二进制文件,然后通过classLoader将class文件加载进内存,生成我们需要的class对象,这个class对象通过反射就可以拿到类的所有信息。在这边的作用其实就是将Java动态生成的class文件进行加载得到动态代理的class对象,以便后面其他操作。
interfaces:这个就是接口,可以看出无论代理或者Man(Dog)都是实现同样的接口,Java替我们动态生成的class文件中的方法其实就是接口中的方法。这个其实也是Java动态代理的缺点,即使Man(Dog)中声明的方法,但是接口中没有声明该方法,那么在生成的代理中就没有,也就是动态生成的代理类中只有接口中的方法。
proxyHandler:一个 InvocationHandler 对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个 InvocationHandler 对象上。集成管理Proxy方法的调用映射到Man(Dog)中,主要就是在invoke中方法实现。
动态代理和静态代理最大的不同就是Java替我们动态生成了代理类代码,代理方法的调用最后都通过InvocationHandler映射到具体的实现类中。
动态代理实现代码:
package com.wechat.management.reflection;
import java.lang.reflect.Proxy;
//动物接口
interface Animal {
public void speak();
}
//人实现类
class Man implements Animal {
@Override
public void speak() {
System.out.println("是人会说话:哈哈哈!!!");
}
}
//狗实现类
class Dog implements Animal {
@Override
public void speak() {
System.out.println("是狗不会说话:汪汪汪!!!");
}
}
//工厂类,多个对象都实现了相同的接口,工厂模式是把这些对象做一个整合,可以通过工厂类获取指定的对象
class Factory {
/**
* 采用反射机制的简单工厂模式
*/
public Object getAnimal(String className) throws Exception {
Class> cls = Class.forName(className);
return cls.newInstance();
}
/**
* 简单工厂模式
*/
public Object getAnimalByType(String type) {
if("com.wechat.management.reflection.Man".equals(type)){
return new Man();
}
if("com.wechat.management.reflection.Dog".equals(type)){
return new Dog();
}
return null;
}
}
//动物代理类,代理类与被代理对象实现相同的接口,代理模式只是隐藏某个对象的行为
class AnimalProxg implements Animal{
//内部指定是哪个被代理的对象
private Animal animalProxg;
public AnimalProxg() {
animalProxg = new Dog();//默认是条狗;外部调用AnimalProxg不知道它是Dog对象
}
//代理里使用工厂
public AnimalProxg(String className) {
try {
Factory factory = new Factory();
this.animalProxg = (Animal) factory.getAnimal(className);;//当狗or当人由外部决定
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public void speak() {
animalProxg.speak();//说话了
}
}
//动态代理类,JDK动态代理:Proxy.newProxyInstance与InvocationHandler的接口实现,动态代理隐藏了对象的方法执行行为
class DynamicProxgHandler {
// 入参:接口对应的Class对象,出参:执行动作(方法)的代理对象
public static Object newProxgInstance(Object target) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), (proxy, method, args) -> {
System.out.println("-----------------------");
Object result = null;
//eg:AOP编程
System.out.println("调用"+target.getClass().getSimpleName()+"的"+method.getName() +"前执行");
//传入参数 invoke(Object obj, Object... args)第一个参数为入参Class对象
result = method.invoke(target, args);
System.out.println("调用"+target.getClass().getSimpleName()+"的"+method.getName() +"后执行");
return result;
});
}
}
//测试类
public class ReflectFactory {
public static void main(String[] args) throws Exception {
//----------工厂模式-------------
System.out.println("----------工厂模式-------------");
Factory factory = new Factory();
Animal man = (Animal) factory.getAnimal("com.wechat.management.reflection.Man");
man.speak();
Animal dog = (Animal) factory.getAnimalByType("com.wechat.management.reflection.Dog");
dog.speak();
//----------代理模式-------------
System.out.println("----------代理模式-------------");
//使用默认值,即默认是条狗
AnimalProxg animalProxg = new AnimalProxg();
animalProxg.speak();
//----------代理+工厂-------------
System.out.println("----------代理+工厂-------------");
//把它当成人了
AnimalProxg animalProxg2 = new AnimalProxg("com.wechat.management.reflection.Man");
animalProxg2.speak();
//----------动态代理-------------
System.out.println("----------动态代理-------------");
Animal animal1 = new Dog();
animal1.speak();//什么都不使用,直接调用方法
Animal animalProxy = (Animal) DynamicProxgHandler.newProxgInstance(new Dog());
animalProxy.speak();//通过动态代理,代理对象执行方法
}
}
执行结果:
----------工厂模式-------------
是人会说话:哈哈哈!!!
是狗不会说话:汪汪汪!!!
----------代理模式-------------
是狗不会说话:汪汪汪!!!
----------代理+工厂-------------
是人会说话:哈哈哈!!!
----------动态代理-------------
是狗不会说话:汪汪汪!!!
-----------------------
调用Dog的speak前执行
是狗不会说话:汪汪汪!!!
调用Dog的speak后执行
带参数的方法实现
package com.wechat.management.reflection;
import java.lang.reflect.Proxy;
public class ReflectProxg {
public static void main(String[] args) {
People people = new Person();
//创建动态代理对象
People peopleProxg = (People) Proxy.newProxyInstance(
people.getClass().getClassLoader(),
people.getClass().getInterfaces(),
(proxy, method, args1) -> {
System.out.println("---------AOP-----------");
return method.invoke(people, args1);
});
//调用接口方法,传入参数,执行结果会给People people
peopleProxg.from("中国");
System.out.println(people);
peopleProxg.from("塞尔维亚");
System.out.println(people);
peopleProxg.from("巴基斯坦");
System.out.println(people);
}
}
interface People {
public void from(String country);
}
class Person implements People{
private String country;
@Override
public void from(String country) {
this.country = country;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
@Override
public String toString() {
return "我是" + country + '人';
}
}
打印结果:
---------AOP-----------
我是中国人
---------AOP-----------
我是塞尔维亚人
---------AOP-----------
我是巴基斯坦人