手动解析配置文件、使用反射机制实例化Bean,彻底理解,结合例子及解析

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.io.InputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class BeanInstantiationExample {
    private Map<String, Object> beanMap = new HashMap<>();

    public BeanInstantiationExample(String configLocation) {
        try {
            // 1. 读取配置文件
            InputStream inputStream = getClass().getClassLoader().getResourceAsStream(configLocation);
            SAXReader reader = new SAXReader();
            Document document = reader.read(inputStream);

            // 2. 获取所有的bean标签
            List<Element> beanElements = document.getRootElement().elements("bean");
            for (Element beanElement : beanElements) {
                // 3. 获取Bean的id和class属性
                String beanId = beanElement.attributeValue("id");
                String beanClassName = beanElement.attributeValue("class");

                // 4. 使用反射机制实例化Bean
                Class<?> beanClass = Class.forName(beanClassName);
                Object beanInstance = beanClass.getDeclaredConstructor().newInstance();

                // 5. 将实例化的Bean对象存放到Map集合中
                beanMap.put(beanId, beanInstance);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public Object getBean(String beanId) {
        return beanMap.get(beanId);
    }

    public static void main(String[] args) {
        // 创建BeanInstantiationExample实例并传入配置文件路径
        BeanInstantiationExample example = new BeanInstantiationExample("applicationContext.xml");

        // 获取实例化的Bean对象
        Object bean1 = example.getBean("bean1");
        Object bean2 = example.getBean("bean2");
        
        // 可以对获取到的Bean对象进行操作
        // ...

        // 示例:使用Spring的ClassPathXmlApplicationContext来获取Bean对象
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        Object springBean1 = context.getBean("bean1");
        Object springBean2 = context.getBean("bean2");
    }
}

解释:

  1. BeanInstantiationExample类中,构造方法BeanInstantiationExample接受一个configLocation参数,用于指定配置文件的路径。
  2. 在构造方法中,首先通过SAXReader读取配置文件,并将其解析为Document对象。
  3. 然后使用XPath表达式document.getRootElement().elements("bean")获取所有的bean元素。
  4. 遍历每个bean元素,获取其idclass属性,使用反射机制实例化对应的Bean对象。
  5. 将实例化的Bean对象存放到beanMap中,以id作为键,Bean对象作为值。
  6. getBean方法用于根据idbeanMap中获取对应的Bean对象。
  7. main方法中,创建BeanInstantiationExample实例并传入配置文件路径,然后可以通过getBean方法获取实例化的Bean对象进行操作。
  8. 示例中还展示了使用Spring的ClassPathXmlApplicationContext来获取Bean对象的方式,用于对比演示。

这段代码演示了如何通过解析配置文件、使用反射机制实例化Bean,并将其存放到Map集合中。这是一个简化的示例,实际应用中可能需要考虑更多的异常处理、Bean作用域、依赖注入等情况。

实例化:

当我们说“实例化”一个对象时,我们是指创建该类的一个具体实例。在Java中,使用new关键字可以实例化一个对象,即在内存中分配空间来存储该对象的数据。实例化一个对象意味着在内存中创建了该类的一个实例,可以通过该实例来访问和操作类中的属性和方法。

在上述代码中,通过反射机制实例化Bean对象意味着我们根据配置文件中指定的类名,动态地实例化该类的对象,而不是在代码中直接写死类名进行实例化。这样做的好处是可以根据配置文件中的信息灵活地实例化不同的类,使代码更具通用性和可配置性。

下面是一个简单的例子,演示了如何使用反射机制实例化一个类的对象:

public class Example {
    public static void main(String[] args) {
        try {
            // 获取类名
            String className = "com.example.MyClass";

            // 使用反射机制实例化类对象
            Class<?> clazz = Class.forName(className);
            Object instance = clazz.getDeclaredConstructor().newInstance();

            // 对实例化的对象进行操作
            // ...
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

getDeclaredConstructor().newInstance():

是使用反射机制来实例化一个类对象的一种方式,它允许我们动态地实例化类,而不需要在编码时知道具体的类名。

在Java中,对于一个类,可以使用Class对象的newInstance()方法来实例化该类的对象。例如:

 

Class<?> clazz = MyClass.class;
 Object instance = clazz.newInstance();

但是,从Java 9开始,newInstance()方法被标记为过时(deprecated),并且在未来的版本中将被移除。因此,推荐使用getDeclaredConstructor().newInstance()来代替newInstance()方法。

getDeclaredConstructor().newInstance()的步骤如下:

  1. 使用getDeclaredConstructor()方法获取类的构造函数(Constructor)对象。
  2. 然后调用newInstance()方法来创建该类的对象。

这种方式更加灵活,因为可以选择特定的构造函数来实例化对象,而不是只能使用无参构造函数。

在上述代码中,通过Class.forName方法获取类名对应的Class对象,然后使用getDeclaredConstructor().newInstance()来实例化该类的对象。

关于将实例化的Bean对象存放到beanMap中的问题

这样做的目的是为了能够根据Bean的id来快速获取对应的实例化对象。在实际应用中,我们可能会需要在不同的地方使用不同的Bean对象,而不需要每次都重新实例化。通过将实例化的Bean对象存放到beanMap中,可以实现对Bean对象的统一管理和快速获取,提高了代码的灵活性和可维护性。

当然,如果您的应用场景中不需要对Bean对象进行统一管理或者不需要根据id来获取Bean对象,那么就没有必要将Bean对象存放到beanMap中。这取决于具体的应用需求。



 

  1. document.getRootElement().elements("bean") 和 selectNodes("//bean") 的区别是:

    • 使用 document.getRootElement().elements("bean") 是基于 DOM 解析,它直接操作整个 XML 文档的树结构,通过遍历元素来获取所需的元素。
    • 而 selectNodes("//bean") 是基于 XPath 查询,它使用 XPath 表达式来定位和选择符合条件的节点。

    以下是相关示例:

     
    // 使用DOM解析方式获取所有的bean元素 
    List<Element> beans1 = document.getRootElement().elements("bean"); 
    // 使用XPath表达式获取所有的bean元素 
    List<Node> beans2 = document.selectNodes("//bean");

  2. 创建 BeanInstantiationExample 实例并传入配置文件路径的原因是,配置文件通常包含了对应类的信息,比如类名、属性等配置。因此,需要将配置文件传入到 BeanInstantiationExample 实例中,以便该实例能够根据配置文件来实例化对应的类对象。

     

    以下是相关示例:

     
    // 创建 BeanInstantiationExample 实例并传入配置文件路径
    BeanInstantiationExample example = new BeanInstantiationExample("path/to/config.xml");

  3. Object 类型的返回值是为了通用性考虑。因为我们可能不知道具体实例化的对象是什么类,所以可以用 Object 类型来接收返回值,然后根据实际情况进行类型转换。

  4. 使用 Spring 的 ClassPathXmlApplicationContext 和自定义的 BeanInstantiationExample 方式获取 Bean 对象的区别在于:

    • Spring 的 ClassPathXmlApplicationContext 是 Spring 框架提供的一种 IoC 容器,它能够管理和装配 Bean 对象,提供了更多的功能和特性。
    • 自定义的 BeanInstantiationExample 可能是一个简化版的 IoC 容器,它可能只实现了基本的 Bean 实例化和管理功能。





      具体解释Spring 的 ClassPathXmlApplicationContext 提供更多功能和特性:

Spring 的 ClassPathXmlApplicationContext 提供了更多的功能和特性,主要体现在以下几个方面:

  1. Bean的生命周期管理:ClassPathXmlApplicationContext 能够管理Bean的生命周期,包括初始化和销毁阶段。通过配置初始化方法和销毁方法,Spring可以在Bean实例化后自动调用这些方法。

  2. AOP(面向切面编程)支持:ClassPathXmlApplicationContext 支持AOP,可以通过配置来实现切面编程,例如日志记录、性能监控等功能,而不需要修改实际的业务逻辑代码。

  3. 事务管理:ClassPathXmlApplicationContext 支持声明式事务管理,可以通过配置来定义事务的边界和传播行为,从而简化事务管理的操作。

  4. 事件监听:ClassPathXmlApplicationContext 支持事件监听机制,可以让Bean在特定事件发生时触发相应的监听器,实现解耦和事件驱动。

以下是一些例子来展示 ClassPathXmlApplicationContext 的功能和特性:

  • Bean的生命周期管理
 
public class ExampleBean {
    private String message;

    // 初始化方法
    public void init() {
        System.out.println("Bean初始化");
    }

    // 销毁方法
    public void destroy() {
        System.out.println("Bean销毁");
    }

    // 省略其他代码
}

在配置文件中指定初始化方法和销毁方法:

 
<bean id="exampleBean" class="com.example.ExampleBean" init-method="init" destroy-method="destroy">
    <property name="message" value="Hello, Spring!"/>
</bean>

  • AOP支持
 
@Aspect
@Component
public class LoggingAspect {
    @Before("execution(* com.example.*.*(..))")
    public void beforeExecution(JoinPoint joinPoint) {
        System.out.println("Before method execution: " + joinPoint.getSignature().getName());
    }
}

在配置文件中启用AOP:

 
<aop:aspectj-autoproxy/>

  • 事务管理
 
@Service
public class ExampleService {
    @Transactional
    public void performTransactionalOperation() {
        // 执行事务操作
    }
}

在配置文件中启用声明式事务管理:

 
<tx:annotation-driven/>

  • 事件监听
 
public class ExampleEvent {
    // 事件定义
}

@Component
public class ExampleListener implements ApplicationListener<ExampleEvent> {
    @Override
    public void onApplicationEvent(ExampleEvent event) {
        // 处理事件
    }
}

在这些例子中,ClassPathXmlApplicationContext 提供了对Bean的生命周期管理、AOP支持、事务管理和事件监听等功能和特性的支持

getClass().getClassLoader().getResourceAsStream(configLocation) :

表示通过当前类的类加载器来获取配置文件的输入流。这种方式通常用于获取类路径下的资源文件。

ClassLoader.getSystemClassLoader().getResourceAsStream(resource) :

则是通过系统类加载器来获取资源文件的输入流,不限于类路径。

以下是相关示例:

 
// 通过当前类的类加载器获取输入流
InputStream input1 = getClass().getClassLoader().getResourceAsStream("config.xml");

// 通过系统类加载器获取输入流
InputStream input2 = ClassLoader.getSystemClassLoader().getResourceAsStream("config.xml");

区别:

  1. 手动解析配置文件实例化所有Bean的方式

    • 该方式是基于dom4j库手动解析XML配置文件,通过读取XML文件中的bean标签,获取bean的id和class属性,然后使用反射机制实例化Bean,并将其存放到Map集合中。
    • 这种方式需要手动编写解析和实例化的代码,相对较为繁琐和复杂,但也更加灵活,可以对Bean的实例化过程进行更细致的控制和处理。
  2. 使用Spring的ClassPathXmlApplicationContext方式
     

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Main {
        public static void main(String[] args) {
            // 加载配置文件并实例化ApplicationContext
            ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
            // 从ApplicationContext中获取所有实例化的Bean
            String[] beanNames = context.getBeanDefinitionNames();
    
            // 输出所有Bean的类名
            for (String beanName : beanNames) {
                System.out.println("Bean Name: " + beanName);
            }
        }
    }
    • 这种方式是利用Spring框架提供的IoC容器ClassPathXmlApplicationContext,它会自动解析配置文件,并实例化ApplicationContext对象,并且可以方便地获取所有实例化的Bean。
    • Spring框架会自动处理配置文件的解析和Bean的实例化过程,使得代码更加简洁和方便,无需手动编写解析和实例化的代码。

总的来说,手动解析配置文件实例化所有Bean的方式更加灵活,但需要编写更多的代码来实现,而使用Spring的ClassPathXmlApplicationContext方式更加简洁和方便,适合快速开发和简单的应用场景。

  • 8
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Tin9898

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值