反射机制和手写IOC

反射基础

从配置文件就可以动态的指定要创建哪个类的对象,创建不同的对象不需要修改源代码

classfullpath=com.xtq.fanshe.bean.Cat
method=hi
arg1=\u5c0f\u82b1
arg2=18

bean包下的实体类  


import lombok.*;

/**
 * @Author: xietianqi
 * @Time: 2024-01-28 14:15
 * @Description:
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class Cat {
	private String name;
	private Integer age;
	public static double weight;
	private Cat(String name){
		this.name=name;
	}
	public void hi(){
		System.out.println("我是"+this.getClass()+"类,我叫"+name+age+"岁了");
	}
}

=====================================================

    
package com.xtq.fanshe.bean;

import lombok.*;

/**
 * @Author: xietianqi
 * @Time: 2024-01-28 14:15
 * @Description:
 */

@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class Dog {
	private String name;
	private Integer age;
	public static double weight;
	private Dog(String name){
		this.name=name;
	}
	public void hi(){
		System.out.println("我是"+this.getClass()+"类,我叫"+name+age+"岁了");
	}
}

使用反射机制创建对象调用方法 

package com.xtq.fanshe;


import org.junit.Test;

import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Properties;

/**
 * @Author: xietianqi
 * @Time: 2024-01-28 14:14
 * @Description: 反射是掌握框架技术的基础
 */
@SuppressWarnings("all")
public class Clazz {
	
	@Test
	public void main() throws Exception {
		/**
		 * 读文件
		 */
		var properties = new Properties();
		properties.load(Files.newInputStream(Paths.get("src/main/resources/re.properties")));
		var classfullpath = properties.get("classfullpath").toString();
		var method = properties.get("method").toString();
		var arg1 = properties.get("arg1").toString();
		var arg2 = Integer.valueOf(properties.get("arg2").toString());
		
		/**
		 * 反射创建对象,得到对象所有信息对象
		 */
		// 根据类名反射得到Class对象
		var clazz = Class.forName(classfullpath);
		// 得到无参构造
		var conNon = clazz.getConstructor();
		// 得到有参构造 ..
		var con = clazz.getConstructor(String.class, Integer.class);
		// 根据clazz类获取对应的对象
		var object = con.newInstance(arg1, arg2);
		// 得到obj运行类型
		System.out.println(object.getClass());
		// 得到方法对象
		var method1 = clazz.getMethod(method);
		//  得到所有权限属性
		var fields1 = clazz.getDeclaredFields();
		// 得到父类
		System.out.println(clazz.getSuperclass());
		// 得到接口
		var interfaces = clazz.getInterfaces();
		
		/**
		 * 访问这些成员对象
		 */
		// 对私有属性进行爆破
		fields1[0].setAccessible(true);
		// 对obj对象的fields[0]设置值
		fields1[0].set(object, "小黄");
		// 查看修改的效果
		System.out.println(object);
		// 设置静态属性值
		fields1[2].set(null, 1.2);
		// 得到静态的属性
		System.out.println(fields1[2].get(null));
		// 调用方法,同理静态的null即可
		method1.invoke(object);
		
		// 带decalared的是不管权限的只拿本类
		// 不带decalared的属性和方法可以拿到父类的
	}
}

IOC容器的基本原理

IOC (inversion of control) 控制反转也叫依赖注入,原理解析xml文件,利用反射机制,在对象工厂中利用反射机制创建对象,目的是为了解耦合,降低对象之间的依赖关系;

举一个不恰当的例子,你在点外卖的时候可以直接打电话给商家订餐,这样你和商家的依赖度就很高,如果借助外卖平台,你就可以在平台上选择不同的商家点单,商家和顾客的耦合度就不高....

而IOC容器就像是这个中间平台一样调度骑手把外卖从商家送到你手上,商家是否能卖出这一单和你是否能吃上饭就取决于这个中间平台;

  • xml文件

    <bean id="userDao" class="com.xtq.dao.UserDao"></bean>
  • 工厂模式+反射类加载

    class UserFactory{
        ...
        public static UserDao getDao(){
            String className = ...// 解析xml获取类的名字
            Class cls = Class.forName(className); // 通过反射创建对象
            return (UserDao) cls.newInstance();
        }
    }

    模拟实现IOC

    • 模拟容器类解析xml文件

    • 使用反射机制创建bean对象

    • 通过反射机制调用set方法,给Bean的属性赋值。

    • 实例化对象进入hashmap (真正的是ConcurrentHashMap)

    package com.xtq.frame;
    ​
    import org.dom4j.Document;
    import org.dom4j.DocumentException;
    import org.dom4j.Element;
    import org.dom4j.Node;
    import org.dom4j.io.SAXReader;
    ​
    import java.lang.reflect.Constructor;
    import java.lang.reflect.Method;
    import java.util.HashMap;
    import java.util.List;
    import java.util.Map;
    ​
    /**
     * @Author: xietianqi
     * @Time: 2024-01-28 14:15
     * @Description:
     */
    ​
    public class ClassPathXmlApplicationContext {
        /**
         * 存储bean的Map集合
         */
        private Map<String, Object> beanMap = new HashMap<>();
        
        /**
         * 在该构造方法中,解析myspring.xml文件,创建所有的Bean实例,并将Bean实例存放到Map集合中。
         *
         * @param resource 配置文件路径(要求在类路径当中)
         */
        public ClassPathXmlApplicationContext(String resource) {
            SAXReader reader = new SAXReader();
            try {
                // 读取配置文件
                Document document = reader.read(resource);
                // 拿到所有的bean标签
                List<Node> beanNodes = document.selectNodes("//bean");
                // 遍历集合拿到对bean进行处理
                beanNodes.forEach(beanNode -> {
                    Element beanElt = (Element) beanNode;
                    // 获取id
                    String id = beanElt.attributeValue("id");
                    // 获取className
                    String className = beanElt.attributeValue("class");
                    try {
                        // 反射获取对象
                        Class<?> clazz = Class.forName(className);
                        Constructor<?> constructor = clazz.getDeclaredConstructor();
                        Object bean = constructor.newInstance();
                        // 存储到Map集合中
                        beanMap.put(id, bean);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                });
                
                
                ///
                ///给对象属性赋值///
                ///
                // 创建和赋值分步进行解决循环依赖
                
                
                beanNodes.forEach(beanNode -> {
                    Element beanElt = (Element) beanNode;
                    // 获取bean的id
                    String beanId = beanElt.attributeValue("id");
                    // 获取所有的property标签
                    List<Element> propertyEls = beanElt.elements("property");
                    propertyEls.forEach(propertyElt -> {
                        try {
                            // 获取属性名
                            String propertyName = propertyElt.attributeValue("name");
                            // 获取属性类型
                            Class<?> propertyType = beanMap.get(beanId).getClass().getDeclaredField(propertyName).getType();
                            // 获取set方法名
                            String setMethodName = "set" + propertyName.toUpperCase().charAt(0) + propertyName.substring(1);
                            // 获取set方法
                            Method setMethod = beanMap.get(beanId).getClass().getDeclaredMethod(setMethodName, propertyType);
                            // 获取value的值
                            String propertyValue = propertyElt.attributeValue("value");
                            
                            
                            // 如果是简单属性
                            if (propertyValue != null) {
                                // 获取属性类型名
                                String simpleName = propertyType.getSimpleName();
                                Object propertyVal = switch (simpleName) {
                                    case "byte", "Byte" -> Byte.valueOf(propertyValue);
                                    case "short", "Short" -> Short.valueOf(propertyValue);
                                    case "int", "Integer" -> Integer.valueOf(propertyValue);
                                    case "long", "Long" -> Long.valueOf(propertyValue);
                                    case "float", "Float" -> Float.valueOf(propertyValue);
                                    case "double", "Double" -> Double.valueOf(propertyValue);
                                    case "boolean", "Boolean" -> Boolean.valueOf(propertyValue);
                                    case "char", "Character" -> propertyValue.charAt(0);
                                    case "String" -> propertyValue;
                                    default -> throw new RuntimeException("这个类还没有设计复杂属性");
                                };
                                setMethod.invoke(beanMap.get(beanId), propertyVal);
                            }
                            
                            // ...
                            
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    });
                    
                });
                
            } catch (DocumentException e) {
                e.printStackTrace();
            }
            
        }
        
        
        public Object getBean(String beanId) {
            return beanMap.get(beanId);
        }
    }
    ​
    • 测试

    package com.xtq.frame;
    ​
    import com.xtq.fanshe.bean.Cat;
    import com.xtq.fanshe.bean.Dog;
    ​
    /**
     * @Author: xietianqi
     * @Time: 2024-01-28 14:15
     * @Description:
     */
    ​
    public class Main {
        public static void main(String[] args) {
            ClassPathXmlApplicationContext ioc = new ClassPathXmlApplicationContext("src/main/resources/beans.xml");
            Object dog = ioc.getBean("dog");
            Object cat = ioc.getBean("cat");
            // ...
            System.out.println(dog.getClass());
            System.out.println(cat.getClass());
            ((Dog) dog).hi();
            ((Cat) cat).hi();
        }
    }
    ​
    • beans.xml内容

      <?xml version="1.0" encoding="UTF-8"?>
      <beans>
      	
      	<bean id="cat" class="com.xtq.fanshe.bean.Cat">
      		<property name="name" value="小xml猫"/>
      		<property name="age" value="19"/>
      	</bean>
      	
      	<bean id="dog" class="com.xtq.fanshe.bean.Dog">
      		<property name="name" value="小xml狗"/>
      		<property name="age" value="19"/>
      	</bean>
      </beans>
    • 结果打印

    class com.xtq.fanshe.bean.Dog 
    class com.xtq.fanshe.bean.Cat 
    我是class com.xtq.fanshe.bean.Dog类,我叫小xml狗19岁了
    我是class com.xtq.fanshe.bean.Cat类,我叫小xml猫19岁了
    

  • 26
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Java反射机制是指在程序运行时动态地获取一个类的信息,包括类的属性、方法和构造函数等,并能够在运行时调用这些属性和方法,而不需要事先知道这个类的具体信息。Java反射机制是实现框架(如Spring)的基础,它使得我们可以在不修改原有代码的情况下,动态地创建对象、调用方法、获取属性等操作,从而实现程序的灵活性和扩展性。 Java反射机制的核心是Class类,每个类都有一个对应的Class对象,它包含了该类的所有信息,包括类名、方法、属性等。通过Class对象可以获取类的信息,并对类进行操作。 Java IOC(Inversion of Control,控制反转)是一种设计模式,它将对象的创建、管理、依赖关系的维护等工作交给容器来完成,从而实现了组件之间的松耦合和可重用性。Java IOC的核心是容器,容器负责管理各个组件之间的依赖关系,并在需要的时候动态地创建和注入对象。 Java IOC的实现依赖于反射机制,容器通过反射机制获取类的信息,并通过构造函数或setter方法来创建和注入对象。Java IOC的好处是可以将各个组件解耦,使得程序更加灵活和可扩展,同时也提高了代码的可测试性和可维护性。 综上所述,Java反射机制是实现Java IOC的基础,Java IOC利用反射机制来实现对象的动态创建和注入。反射机制IOC的合理运用可以使程序更加灵活和可扩展。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值