AI摘要 本文总结了Java Spring IoC的整体流程，重点涵盖了Spring Bean的基本实例化过程、BeanFactory后处理器的执行逻辑以及Bean生命周期的各个阶段。通过对核心环节的梳理，清晰展示了Spring容器管理Bean的完整机制。 此内容根据文章生成，仅用于文章内容的解释与总结 Java Spring IoC整体流程总结1. 整体流程2. SpringBean基本实例化过程3. BeanFactory后处理器过程4. Bean生命周期阶段
AI摘要 Spring Bean生命周期分为实例化、初始化和完成阶段。实例化后，在初始化阶段进行属性填充、Aware接口注入及BeanPostProcessor回调。针对循环依赖，Spring通过三级缓存机制解决。最终，完整Bean存入单例池完成生命周期。 此内容根据文章生成，仅用于文章内容的解释与总结 Java Spring 生命周期1. 概述Spring Bean的生命周期是从 Bean 实例化之后，即通过反射创建出对象之后，到Bean成为一个完整对象，最终存储到单例池中，这个过程被称为Spring Bean的生命周期。Spring Bean的生命周期大体上分为三个阶段:Bean的实例化阶段: Spring框架会取出BeanDefinition的信息进行判断当前Bean的范围是否是sinaleton的是否不是延迟加载的，是否不是FactoryBean等，最终将一个普通的singleton的Bean通过反射进行实例化;Bean的初始化阶段: Bean创建之后还仅仅是个"半成品”，还需要对Bean实例的属性进行填充、执行一些Aware接口方法、执行BeanPostProcessor方法、执行InitializingBean接口的初始化方法、执行自定义初始化init方法等。该阶段是Spring最具技术含量和复杂度的阶段，Aop增强功能，后面要学习的Spring的注解功能等spring高频面试题Bean的循环引用问题都是在这个阶段体现的:Bean的完成阶段: 经过初始化阶段，Bean就成为了一个完整的Spring Bean，被存储到单例池singletonObjects中去了，即完成了Spring Bean的整个生命周期2. 初始化阶段2.1 Bean的初始化阶段涉及过程Spring Bean的初始化过程涉及如下几个过程Bean实例的属性填充Aware接口属性注入BeanPostProcessor的before()方法回调InitializingBean接口的初始化方法回调自定义初始化方法init回调BeanPostProcessor的after()方法回调2.2 Bean实例属性填充Spring在进行属性注入时，会分为如下几种情况:注入普通属性，String、int或存储基本类型的集合时，直接通过set方法的反射设置进去;注入单向对象引用属性时，从容器中getBean获取后通过set方法反射设置进去，如果容器中没有，则先创建被注入对象Bean实例(完成整个生命周期)后，在进行注入操作;注入双向对象引用属性时，就比较复杂了，涉及了循环引用(循环依赖)问题2.2.1 propertyValuesBeanDefinition 中有对当前Bean实体的注入信息通过属性propertyValues进行了存储PersonDao.javapackage org.example; public interface PersonDao { }UserDao.javapackage org.example; public interface UserDao { }UserDaoImpl.javapackage org.example; public class UserDaoImpl implements UserDao { }PersonDaoImpl.javapackage org.example; public class PersonDaoImpl implements PersonDao{ public String getName() { return name; } public void setName(String name) { this.name = name; } public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } private String name; private UserDao userDao; } beans.xml<bean class="org.example.UserDaoImpl" id="userDao"/> <bean class="org.example.PersonDaoImpl" id="personDao"> <property name="userDao" ref="userDao"/> <property name="name" value="名字"/> </bean>主函数调用ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");例如PersonDao的属性信息如下:2.2.2 循环引用多个实体之间相互依赖并形成闭环的情况就叫做”循环依赖”，也叫做”循环引用。死循环原理图UserDaoImpl.javapackage org.example; public class UserDaoImpl implements UserDao { private UserService userService; public UserService getUserService() { return userService; } public void setUserService(UserService userService) { this.userService = userService; } } UserServiceImpl.javapackage org.example; public class UserServiceImpl implements UserService { private UserDao userDao; public UserDao getUserDao() { return userDao; } public void setUserDao(UserDao userDao) { this.userDao = userDao; } } beans.xml<bean class="org.example.UserDaoImpl" id="userDao"> <property name="userService" ref="userService"/> </bean> <bean class="org.example.UserServiceImpl" id="userService"> <property name="userDao" ref="userDao"/> </bean>2.2.3 三级缓存解决循环引用问题Spring提供了三级缓存存储完整Bean实例和半成品Bean实例，用于解决循环引用问题在DefaultListableBeanFactory的上四级父类DefaultSingletonBeanRegistry中提供如下三个Map:UserService和UserDao循环依赖的过程结合上述三级缓存描述一下UserService 实例化对象，但尚未初始化，将UserService存储到三级缓存UserService 属性注入，需要UserDao，从缓存中获取，没有UserDao;UserDao实例化对象，但尚未初始化，将UserDao存储到到三级缓存;UserDao属性注入，需要UserService，从三级缓存获取UserService，UserService从三级缓存移入二级缓存:UserDao执行其他生命周期过程，最终成为一个完成Bean，存储到一级缓存，删除二三级缓存UserService 注入UserDao:UserService执行其他生命周期过程，最终成为一个完成Bean，存储到一级缓存，删除二三级缓存2.3 常用的Aware接口Aware接口是一种框架辅助属性注入的一种思想，其他框架中也可以看到类似的接口。框架具备高度封装性，我们接触到的一般都是业务代码，一个底层功能API不能轻易的获取到，但是这不意味着永远用不到这些对象，如果用到了就可以使用框架提供的类似Aware的接口，让框架给我们注入该对象。在pom.xml添加ServletContext依赖jar包 <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> </dependency>UserServiceImpl.javapackage org.example; import org.springframework.beans.BeansException; import org.springframework.beans.factory.BeanFactory; import org.springframework.beans.factory.BeanFactoryAware; import org.springframework.beans.factory.BeanNameAware; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; public class UserServiceImpl implements UserService, ApplicationContextAware, BeanNameAware, BeanFactoryAware { public UserServiceImpl() { System.out.println("构造方法执行"); } @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("BeanFactory--------" + beanFactory.toString()); } @Override public void setBeanName(String s) { System.out.println("BeanName--------" + s); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("ApplicationContext--------" + applicationContext.toString()); } } 主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); System.out.println(userService); }执行结果构造方法执行 BeanName--------userService BeanFactory--------org.springframework.beans.factory.support.DefaultListableBeanFactory@319b92f3: defining beans [userDao,userService]; root of factory hierarchy ApplicationContext--------org.springframework.context.support.ClassPathXmlApplicationContext@1a93a7ca, started on Sat Mar 04 15:19:28 CST 2023 org.example.UserServiceImpl@436a4e4b{x}
AI摘要 本文介绍了Spring两大核心扩展点：BeanFactoryPostProcessor用于在Bean实例化前动态修改或注册BeanDefinition；BeanPostProcessor则在Bean初始化前后介入，常用于属性填充或通过动态代理实现功能增强。两者为开发者提供了介入Bean生命周期的灵活机制。 此内容根据文章生成，仅用于文章内容的解释与总结 Java Spring Bean工厂后处理器Spring的后处理器是Spring对外开发的重要扩展点，允许我们介入到Bean的整个实例化流程中来，以达到动态注册BeanDefinition，动态修改BeanDefinition，以及动态修改Bean的作用。Spring主要有两种后处理器:BeanFactoryPostProcessor: Bean工厂后处理器，在BeanDefinitionMap填充完毕，Bean实例化之前执行；BeanPostProcessor: Bean后处理器，一般在Bean实例化之后，填充到单例池singletonObjects之前执行。1. BeanFactoryPostProcessor1.1 快速入门BeanFactoryPostProcessor是一个接口规范，实现了该接口的类只要交由Spring容器管理的话，那么Spring就会回调该接口的方法，用于对BeanDefinition注册和修改的功能。实例化流程MyBeanFactoryPostProcessor.javapackage processor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanFactoryPostProcessor; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { System.out.println("beanDefinitionMap填充完毕后回调该方法"); } } beans.xml<bean class="processor.MyBeanFactoryPostProcessor"/>主函数断点调试public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); }执行结果beanDefinitionMap填充完毕后回调该方法1.2 强制修改BeanDefinition其他设置基于上文MyBeanFactoryPostProcessor.javapublic class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { System.out.println("beanDefinitionMap填充完毕后回调该方法"); BeanDefinition beanDefinition = configurableListableBeanFactory.getBeanDefinition("userService"); beanDefinition.setBeanClassName("org.example.UserDaoImpl"); } }主函数调用public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Object userService = applicationContext.getBean("userService"); System.out.println(userService); }输出结果beanDefinitionMap填充完毕后回调该方法 org.example.UserDaoImpl@3c875211.3 动态注入BeanDefinition创建一个新的接口PersonDaopublic interface PersonDao { }创建一个新的类PersonDaoImpl，并且继承PersonDao接口public class PersonDaoImpl implements PersonDao{ }MyBeanFactoryPostProcessor.javapublic class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { System.out.println("beanDefinitionMap填充完毕后回调该方法"); //注册BeanDefinition BeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClassName(PersonDaoImpl.class.getName()); //强转为DefaultListableBeanFactory DefaultListableBeanFactory defaultListableBeanFactory = (DefaultListableBeanFactory) configurableListableBeanFactory; defaultListableBeanFactory.registerBeanDefinition("personDao",beanDefinition); } }beans.xml<bean class="processor.MyBeanFactoryPostProcessor"/>主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); PersonDao personDao = applicationContext.getBean(PersonDao.class); System.out.println(personDao); }执行结果beanDefinitionMap填充完毕后回调该方法 org.example.PersonDaoImpl@780cb77_Spring 提供了一个BeanFactoryPostProcessor的子接口BeanDefinitionRegistryPostProcessor专门用于注册BeanDefinition操作直接继承BeanDefinitionRegistryPostProcessor接口的方式简化代码MyBeanDefinitionRegistryPostProcessor.javapackage processor; import org.example.PersonDaoImpl; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { System.out.println("beanDefinitionMap填充完毕后回调该方法"); //注册BeanDefinition BeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClassName(PersonDaoImpl.class.getName()); beanDefinitionRegistry.registerBeanDefinition("personDao",beanDefinition); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { } } beans.xml<bean class="processor.MyBeanDefinitionRegistryPostProcessor"/>主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); PersonDao personDao = applicationContext.getBean(PersonDao.class); System.out.println(personDao); }执行结果beanDefinitionMap填充完毕后回调该方法 org.example.PersonDaoImpl@50a7bc6e1.4使用Spring的BeanFactoryPostProcessor扩展点完成自定义注解扫描要求如下：自定义@MyComponent注解，使用在类上;使用资料中提供好的包扫描器工具BaseClassScanUtils 完成指定包的类扫描自定义BeanFactoryPostProcessor完成注解@MyComponent的解析，解析后最终被Spring管理。黑马程序员提供的BaseClassScanUtils.javapackage com.itheima.utils; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.type.classreading.CachingMetadataReaderFactory; import org.springframework.core.type.classreading.MetadataReader; import org.springframework.core.type.classreading.MetadataReaderFactory; import org.springframework.util.ClassUtils; import java.lang.annotation.Annotation; import java.util.HashMap; import java.util.List; import java.util.Map; public class BaseClassScanUtils { //设置资源规则 private static final String RESOURCE_PATTERN = "/**/*.class"; public static Map<String, Class> scanMyComponentAnnotation(String basePackage) { //创建容器存储使用了指定注解的Bean字节码对象 Map<String, Class> annotationClassMap = new HashMap<String, Class>(); //spring工具类，可以获取指定路径下的全部类 ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); try { String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(basePackage) + RESOURCE_PATTERN; Resource[] resources = resourcePatternResolver.getResources(pattern); //MetadataReader 的工厂类 MetadataReaderFactory refractory = new CachingMetadataReaderFactory(resourcePatternResolver); for (Resource resource : resources) { //用于读取类信息 MetadataReader reader = refractory.getMetadataReader(resource); //扫描到的class String classname = reader.getClassMetadata().getClassName(); Class<?> clazz = Class.forName(classname); //判断是否属于指定的注解类型 if(clazz.isAnnotationPresent(MyComponent.class)){ //获得注解对象 MyComponent annotation = clazz.getAnnotation(MyComponent.class); //获得属value属性值 String beanName = annotation.value(); //判断是否为"" if(beanName!=null&&!beanName.equals("")){ //存储到Map中去 annotationClassMap.put(beanName,clazz); continue; } //如果没有为"",那就把当前类的类名作为beanName annotationClassMap.put(clazz.getSimpleName(),clazz); } } } catch (Exception exception) { } return annotationClassMap; } public static void main(String[] args) { Map<String, Class> stringClassMap = scanMyComponentAnnotation("com.itheima"); System.out.println(stringClassMap); } }由于我使用的是jdk19，所以使用上述文件会提示版本错误，所以在上面的基础上进行修改package utils; import anno.MyComponent; import org.springframework.core.io.Resource; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.util.ClassUtils; import java.util.HashMap; import java.util.Map; public class BaseClassScanUtils { //设置资源规则 private static final String RESOURCE_PATTERN = "/**/*.class"; public static Map<String, Class> scanMyComponentAnnotation(String basePackage) { //创建容器存储使用了指定注解的Bean字节码对象 Map<String, Class> annotationClassMap = new HashMap<String, Class>(); //spring工具类，可以获取指定路径下的全部类 ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); try { String pattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + ClassUtils.convertClassNameToResourcePath(basePackage) + RESOURCE_PATTERN; Resource[] resources = resourcePatternResolver.getResources(pattern); for (Resource resource : resources) { Class<?> clazz = Class.forName(resource.getFile().toString().split("classes\\\\")[1].replaceAll("\\\\",".").split(".class")[0]); //判断是否属于指定的注解类型 if(clazz.isAnnotationPresent(MyComponent.class)){ //获得注解对象 MyComponent annotation = clazz.getAnnotation(MyComponent.class); //获得属value属性值 String beanName = annotation.value(); //判断是否为"" if(beanName!=null&&!beanName.equals("")){ //存储到Map中去 annotationClassMap.put(beanName,clazz); continue; } //如果没有为"",那就把当前类的类名作为beanName annotationClassMap.put(clazz.getSimpleName(),clazz); } } } catch (Exception exception) { System.out.println(exception); } return annotationClassMap; } public static void main(String[] args) { Map<String, Class> stringClassMap = scanMyComponentAnnotation("beans"); System.out.println(stringClassMap); } }创建注解MyComponentpackage anno; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface MyComponent { String value(); }创建类并且添加MyComponent注解，类位于beans目录下package beans; import anno.MyComponent; @MyComponent("otherBean") public class OtherBean { }创建新的后工厂处理器类，并且继承BeanDefinitionRegistryPostProcessor接口package processor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; import utils.BaseClassScanUtils; import java.util.Map; public class MyComponentBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { // 使用扫描工具去扫描指定包以及子包下的所有类，收集使用@Mycomponent的注解的类 Map<String, Class> myComponentAnnotation = BaseClassScanUtils.scanMyComponentAnnotation("beans"); // 遍历Map，组装BeanDefinition进行注册 myComponentAnnotation.forEach((beanName,clazz)->{ // 获取类名 String beanClassName = clazz.getName(); // 创建BeanDefinition BeanDefinition beanDefinition = new RootBeanDefinition(); beanDefinition.setBeanClassName(beanClassName); // 注册BeanDefinition beanDefinitionRegistry.registerBeanDefinition(beanName ,beanDefinition); }); } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { } } 在beans.xml中添加后工厂处理器<bean class="processor.MyComponentBeanFactoryPostProcessor"/>主函数调用public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); OtherBean otherBean = applicationContext.getBean(OtherBean.class); System.out.println(otherBean); }执行结果beans.OtherBean@2133814f2. BeanPostProcessor2.1 快速入门Bean被实例化后，到最终缓存到名为singletonObjects单例池之前，中间会经过Bean的初始化过程，例如: 属性的填充、初始方法init的执行等，其中有一个对外进行扩展的点BeanPostProcessor，我们称为Bean后处理。跟上面的Bean工厂后处理器相似，它也是一个接口，实现了该接口并被容器管理的BeanPostProcessor，会在流程节点上被Spring自动调用。BeanPostProcessor类public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }UserDaopackage org.example; public interface UserDao { }UserDaoImplpackage org.example; public class UserDaoImpl implements UserDao { String name; public UserDaoImpl() { System.out.println("UserDaoImpl初始化"); } public String getName() { return name; } public void setName(String name) { System.out.println("设置name的值为" + name); this.name = name; } }创建MyBeanPostProcessor并且继承BeanPostProcessor接口public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("before-" + beanName + ":" + bean.toString()); if (bean instanceof UserDaoImpl){ UserDaoImpl userDao = (UserDaoImpl) bean; userDao.setName("hhhhh"); } return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName); } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("after-" + beanName + ":" + bean.toString()); return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName); } }beans.xml<bean class="processor.MyBeanPostProcessor"/> <bean class="org.example.UserDaoImpl" id="userDao"/>主函数执行public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserDaoImpl userDao = (UserDaoImpl) applicationContext.getBean("userDao"); System.out.println(userDao.getName()); }执行结果UserDaoImpl初始化 before-userDao:org.example.UserDaoImpl@646be2c3 设置name的值为hhhhh after-userDao:org.example.UserDaoImpl@646be2c3 hhhhh2.2 before和after方法的执行时机基于上述快速入门的文件进行修改UserDaoImpl.javapackage org.example; import org.springframework.beans.factory.InitializingBean; public class UserDaoImpl implements UserDao, InitializingBean { public UserDaoImpl() { System.out.println("UserDaoImpl初始化"); } String name; public String getName() { return name; } public void setName(String name) { System.out.println("设置name的值为" + name); this.name = name; } public void init(){ System.out.println("init初始化方法执行"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("属性设置之后执行"); } }beans.xml<bean class="org.example.UserDaoImpl" id="userDao" init-method="init"/> <bean class="processor.MyBeanPostProcessor" />执行结果UserDaoImpl初始化 before-userDao:org.example.UserDaoImpl@3c0a50da 设置name的值为hhhhh 属性设置之后执行 init初始化方法执行 after-userDao:org.example.UserDaoImpl@3c0a50da hhhhh2.3 对Bean方法进行执行时间日志增强需求：Bean的方法执行之前控制台打印当前时间Bean的方法执行之后控制台打印当前时间分析：对方法进行增强主要就是代理设计模式和包装设计模式由于Bean方法不确定，所以使用动态代理在运行期间执行增强操作在Bean实例创建完毕后，进入到单例池之前，使用Proxy代替真是的目标BeanUserDao.javapackage org.example; public interface UserDao { public void show(); }UserDaoImpl.javapackage org.example; public class UserDaoImpl implements UserDao { public void show(){ System.out.println("执行方法中"); } }TimeLogBeanPostProcessor.javapackage processor; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Date; public class TimeLogBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { Object beanProxy = Proxy.newProxyInstance(bean.getClass().getClassLoader(), bean.getClass().getInterfaces(), (Object proxy, Method method, Object[] args) -> { //1.输出开始时间 System.out.println("方法：" + method.getName() + "-开始时间：" + new Date()); //2.执行目标方法 Object result = method.invoke(bean,args); //3.输出结束时间 System.out.println("方法：" + method.getName() + "-结束时间：" + new Date()); return result; }); return beanProxy; } }beans.xml<bean class="processor.TimeLogBeanPostProcessor"/> <bean class="org.example.UserDaoImpl" id="userDao"/>主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); userDao.show(); }执行结果方法：show-开始时间：Thu Mar 02 16:13:42 CST 2023 执行方法中 方法：show-结束时间：Thu Mar 02 16:13:43 CST 2023
AI摘要 Spring Bean实例化流程如下：首先解析配置文件，将Bean信息封装为BeanDefinition并存入beanDefinitionMap；随后容器遍历该Map，通过反射创建Bean实例并存入singletonObjects集合；最终调用getBean方法时，直接从singletonObjects中获取并返回对应的Bean实例。 此内容根据文章生成，仅用于文章内容的解释与总结 Java Spring Bean实例化的基本流程Spring容器在进行初始化时，会将xml配置的<bean>的信息封装成一个BeanDefinition对象，所有的BeanDefinition存储到一个名为beanDefinitionMap的Map集合中去，Spring框架在对该Map进行遍历，使用反射创建Bean实例对象，创建好的Bean对象存储在一个名为singletonObjects的Map集合中，当调用getBean方法时则最终从该Map集合中取出Bean实例对象返回。流程：加载xml配置文件，解析获取配置中的每个<bean>的信息，封装成一个个的BeanDefinition对象将BeanDefinition存储在一个名为beanDefinitionMap的Map<String,BeanDefinition>中;ApplicationContext底层遍历beanDefinitionMap，创建Bean实例对象 创建好的Bean实例对象，被存储到一个名为singletonObjects的Map<String,Object>中;当执行applicationContext.getBean(beanName)时，从singletonObjects去匹配Bean实例返回beans.xml <bean class="org.example.UserDaoImpl" id="userDao"/> <bean class="org.example.UserServiceImpl" id="userService"/>主函数断点调试运行 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); }Bean信息定义对象-BeanDefinitionBeanDefinition.class// // Source code recreated from a .class file by IntelliJ IDEA // (powered by FernFlower decompiler) // package org.springframework.beans.factory.config; import org.springframework.beans.BeanMetadataElement; import org.springframework.beans.MutablePropertyValues; import org.springframework.core.AttributeAccessor; import org.springframework.core.ResolvableType; import org.springframework.lang.Nullable; public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement { String SCOPE_SINGLETON = "singleton"; String SCOPE_PROTOTYPE = "prototype"; int ROLE_APPLICATION = 0; int ROLE_SUPPORT = 1; int ROLE_INFRASTRUCTURE = 2; void setParentName(@Nullable String var1); @Nullable String getParentName(); void setBeanClassName(@Nullable String var1); @Nullable String getBeanClassName(); void setScope(@Nullable String var1); @Nullable String getScope(); void setLazyInit(boolean var1); boolean isLazyInit(); void setDependsOn(@Nullable String... var1); @Nullable String[] getDependsOn(); void setAutowireCandidate(boolean var1); boolean isAutowireCandidate(); void setPrimary(boolean var1); boolean isPrimary(); void setFactoryBeanName(@Nullable String var1); @Nullable String getFactoryBeanName(); void setFactoryMethodName(@Nullable String var1); @Nullable String getFactoryMethodName(); ConstructorArgumentValues getConstructorArgumentValues(); default boolean hasConstructorArgumentValues() { return !this.getConstructorArgumentValues().isEmpty(); } MutablePropertyValues getPropertyValues(); default boolean hasPropertyValues() { return !this.getPropertyValues().isEmpty(); } void setInitMethodName(@Nullable String var1); @Nullable String getInitMethodName(); void setDestroyMethodName(@Nullable String var1); @Nullable String getDestroyMethodName(); void setRole(int var1); int getRole(); void setDescription(@Nullable String var1); @Nullable String getDescription(); ResolvableType getResolvableType(); boolean isSingleton(); boolean isPrototype(); boolean isAbstract(); @Nullable String getResourceDescription(); @Nullable BeanDefinition getOriginatingBeanDefinition(); }
AI摘要 本文介绍了如何在Spring中配置非自定义Bean（第三方类）。通过Druid数据源、JDBC连接、日期对象及MyBatis的SqlSessionFactory等实例，展示了利用无参构造、静态工厂方法及实例工厂方法三种方式，实现第三方Bean的实例化与属性注入，从而将其纳入Spring容器管理。 此内容根据文章生成，仅用于文章内容的解释与总结 Java Spring 配置非自定义Bean0.介绍实际开发中会使用第三方jar包中的功能类，这些Bean要想让Spring进行管理，也需要对其进行配置两个问题：被配置的Bean实例化方式是什么被配置的Bean是否需要注入必要属性1.配置Druid数据源交由Spring管理maven配置文件导入相应jar包pom.xml <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.23</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency>beans.xml <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver" /> <property name="url" value="jdbc:mysql://localhost:3306/java"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean>主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Object dataSource = applicationContext.getBean("dataSource"); System.out.println(dataSource); }运行结果{ CreateTime:"2023-02-26 17:23:51", ActiveCount:0, PoolingCount:0, CreateCount:0, DestroyCount:0, CloseCount:0, ConnectCount:0, Connections:[ ] }2.配置Connection交由Spring管理Connection的产生是通过DriverManager的静态方法getConnection获取的，所以我们要用静态工厂的方式配置beans.xml（getConnection报红不用管） <bean id="connection" class="java.sql.DriverManager" factory-method="getConnection" scope="prototype"> <constructor-arg name="url" value="jdbc:mysql://localhost:3306/java"/> <constructor-arg name="user" value="root"/> <constructor-arg name="password" value="root"/> </bean>主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Object connection = applicationContext.getBean("connection"); System.out.println(connection);; }执行结果（报错不用管，看到有类字节码地址输出即可）com.mysql.jdbc.JDBC4Connection@42a15bdc3.配置日期对象交由Spring管理原生使用日期对象 SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Date date = simpleDateFormat.parse("2023-08-27 12:00:00"); System.out.println(date);结果输出Sun Aug 27 12:00:00 CST 2023配置日期对象交由Spring管理beans.xml <bean id="simpleDateFormat" class="java.text.SimpleDateFormat"> <constructor-arg name="pattern" value="yyyy-MM-dd HH:mm:ss"/> </bean> <bean id="date" factory-bean="simpleDateFormat" factory-method="parse"> <constructor-arg name="source" value="2023-08-27 12:00:00"/> </bean>主函数执行 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); Object date1 = applicationContext.getBean("date"); System.out.println(date1);结果输出Sun Aug 27 12:00:00 CST 20234.配置MyBatis的SqlSessionFactory交由Spring管理导入MyBatis的相关坐标 <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.5</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.49</version> </dependency>4.1 原生实现 // 静态工厂方法方式 InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml"); // 无参构造实例化 SqlSessionFactoryBuilder sqlSessionFactoryBuilder = new SqlSessionFactoryBuilder(); // 实例工厂方法 SqlSessionFactory sqlSessionFactory = sqlSessionFactoryBuilder.build(inputStream); System.out.println(sqlSessionFactory);执行结果org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@79efed2d4.2 Bean实现resources目录下创建mybatis-config.xml<?xml version="1.0" encoding="UTF-8" ?> <configuration> <environments default="development"> <environment id="development"> <transactionManager type="JDBC"/> <dataSource type="POOLED"> <property name="driver" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/java"/> <property name="username" value="root"/> <property name="password" value="root"/> </dataSource> </environment> </environments> </configuration>beans.xml <bean id="resources" class="org.apache.ibatis.io.Resources" factory-method="getResourceAsStream"> <constructor-arg name="resource" value="mybatis-config.xml"/> </bean> <bean id="sqlSessionFactoryBuilder" class="org.apache.ibatis.session.SqlSessionFactoryBuilder"/> <bean id="sqlSessionFactory" factory-bean="sqlSessionFactoryBuilder" factory-method="build"> <constructor-arg name="inputStream" ref="resources"/> </bean>主函数调用 ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Object sqlSessionFactory = applicationContext.getBean("sqlSessionFactory"); System.out.println(sqlSessionFactory);执行结果org.apache.ibatis.session.defaults.DefaultSqlSessionFactory@5026735c
AI摘要 Spring框架支持通过``标签的`autowire`属性实现自动装配。`byName`根据属性名匹配Bean的id，`byType`根据类型匹配。若使用`byType`时容器中存在多个同类型Bean，系统将抛出异常，无法完成自动装配。 此内容根据文章生成，仅用于文章内容的解释与总结 Java Spring 自动装配如果被注入的属性类型是Bean引用的话，那么可以在<bean>标签中使用autowire属性去配置自动注入方式，属性值有两个byName：通过属性名自动装配，即去匹配setXxx与id="xxx"(name="xxx")是否一致；byType：通过Bean的类型从容器中匹配，匹配出多个相同Bean类型，报错。beans.xml<bean class="org.example.UserDaoImpl" id="userDao"/> <bean class="org.example.UserServiceImpl" id="userService" autowire="byName"/> <bean class="org.example.UserServiceImpl" id="userService1" autowire="byType"/>UserServicepublic interface UserService { public void show(); }UserServiceImplpublic class UserServiceImpl implements UserService { private UserDao userDao; public void setUserDao(UserDao userDao){ this.userDao = userDao; } @Override public void show() { System.out.println(userDao); } }主函数调用public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); ((UserService) applicationContext.getBean("userService")).show(); ((UserService) applicationContext.getBean("userService1")).show(); }执行结果org.example.UserDaoImpl@1f0f1111 org.example.UserDaoImpl@1f0f1111如果xml文件自动装配中有多个同类型的bean容器将会报错例如：<bean class="org.example.UserDaoImpl" id="userDao"/> <bean class="org.example.UserDaoImpl" id="userDao1"/> <bean class="org.example.UserServiceImpl" id="userService" autowire="byName"/> <bean class="org.example.UserServiceImpl" id="userService1" autowire="byType"/>IDEA报错提示无法自动装配。存在多个 'UserDao' 类型的 Bean。Bean: userDao1,userDao。属性: 'userDao'运行结果提示警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService1' defined in class path resource [beans.xml]: Unsatisfied dependency expressed through bean property 'userDao'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.example.UserDao' available: expected single matching bean but found 2: userDao,userDao1 Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'userService1' defined in class path resource [beans.xml]: Unsatisfied dependency expressed through bean property 'userDao'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'org.example.UserDao' available: expected single matching bean but found 2: userDao,userDao1
AI摘要 本文介绍了基于XML的Spring应用开发，涵盖了Bean的基础配置、作用范围（singleton/prototype）、延迟加载、生命周期方法（init/destroy）、实例化方式（构造、工厂、FactoryBean）以及依赖注入（List、Set、Map等集合类型）的详细配置方法。 此内容根据文章生成，仅用于文章内容的解释与总结 Java 基于xml的Spring应用1.SpringBean 的配置解析Spring开发中主要是对Bean的配置，Bean的常用配置一览如下： 1.Bean的基础配置配置UserDaoImpl由Spring容器负责管理<bean id="userDao" class="org.example.UserDaoImpl"></bean>此时存储到Spring容器（singleObjects单例池）中的Bean的beanName是userDao，值是UserDaoImpl对象，可以根据beanName获取Bean实例applicationContext.getBean("userDao")如果不配置id，则Spring会把当前Bean实例的全限定名作为beanNamepublic static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserDao bean = (UserDao) applicationContext.getBean("org.example.UserDaoImpl"); System.out.println(bean); }如果配置了id，便不能在使用Bean实例的全限定名进行获取，例如：applicationContext.getBean("org.example.UserDaoImpl");配置别名，配置别名后可以使用别名获得Bean对象实例<bean id="userDao" name="aaa,bbb" class="org.example.UserDaoImpl"></bean>2.SpringBean的配置详解1.Bean的范围配置默认情况下，单纯的Spring环境Bean的作用范围有两个：Singleton和Prototypesingleton：单例，默认值，Spring容器创建的时候，就会进行Bean的实例化，并且存储到容器内部的单例池中，每次getBean时都是从单例池中获取相同的Bean实例<bean id="userDao" class="org.example.UserDaoImpl" scope="singleton"></bean>prototype：原型，Spring容器初始化时不会创建Bean实例，只有调用getBean时才会实例化Bean，每次getBean都会创建一个新的Bean实例<bean id="userDao" class="org.example.UserDaoImpl" scope="prototype"></bean>如果是spring-webmvc的情况下，还会增加两个作用范围：request和sessionmaven导包<dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.7</version> </dependency>request：将创建的对象放在request域当做<bean id="userDao" class="org.example.UserDaoImpl" scope="request"></bean>session：将创建的对象放在session域当做<bean id="userDao" class="org.example.UserDaoImpl" scope="session"></bean>2.Bean的延迟加载当lazy-init设置为true时为延迟加载，也就是当Spring容器创建的时候，不会立即创建Bean实例，等待用到时在创建Bean实例并且存储到单例池中去，后续在使用该Bean直接冲单例池获取，本质上该Bean还是单例的，只对scope设置为singleton的Bean起作用，对prototype无效，对BeanFactory作为容器也无效<bean id="userDao" class="org.example.UserDaoImpl" lazy-init="true"></bean>3.Bean的初始化方法和销毁方法init-method：初始化时运行方法destroy-method：销毁时运行方法，单例模式容器必须显示关闭才会执行这个方法，否则不会执行关闭，又因为ApplicationContext的接口没有关闭容器的方法，所以类型需要使用ClassPathXmlApplicationContext，才有close显式关闭容器，如果不使用显式关闭，则有可能不会执行销毁方法，例如容器挂掉后就无法执行销毁方法beans.xml:<bean id="userDao" class="org.example.UserDaoImpl" init-method="init" destroy-method="destroy"></bean>UserDaoImpl.javapublic class UserDaoImpl implements UserDao{ public void init(){ System.out.println("初始化方法"); } public void destroy(){ System.out.println("销毁方法"); } }主函数调用 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); System.out.println(userDao); applicationContext.close(); }结果输出初始化方法 org.example.UserDaoImpl@7d68ef40 销毁方法扩展：除此之外，我们还可以通过实现InitializingBean接口，完成一些Bean的初始化操作，比init-method方法优先级要高UserDaoImpl.javapublic class UserDaoImpl implements UserDao, InitializingBean { public void init(){ System.out.println("初始化方法"); } public void destroy(){ System.out.println("销毁方法"); } @Override public void afterPropertiesSet() throws Exception { System.out.println("属性执行之后进行调用"); } }主函数调用public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserDao userDao = (UserDao) applicationContext.getBean("userDao"); System.out.println(userDao); applicationContext.close(); }结果输出属性执行之后进行调用 初始化方法 org.example.UserDaoImpl@5b0abc94 销毁方法4.Bean的实例化配置Spring的实例化方式主要如下两种：构造方式实例化：底层通过构造方法对Bean进行实例化工厂方式实例化：底层通过调用自定义的工厂方法对Bean进行实例化构造方式实例化Bean分为有参构造和无参构造方法实例化，Spring中配置的<bean>几乎都是无参构造，有参构造例子如下：UserDaoImpl.javapublic class UserDaoImpl implements UserDao { public UserDaoImpl(String name){ System.out.println(name); } }有参构造在实例化Bean时，需要参数的注入，通过constructor-arg标签，嵌入在bean标签内部提供构造参数beans.xml<bean id="userDao" class="org.example.UserDaoImpl"> <constructor-arg value="你好"/> </bean>工厂方式实例化Bean，又分为如下三种：静态工厂方法实例化Bean实例工厂方法实例化Bean实现FactoryBean规范延迟实例化Bean静态工厂实例化Bean：创建一个静态方法public class MyBeanFactory1 { public static UserDao userDao(){ return new UserDaoImpl(); } }配置beans.xml文件，factory-method指定静态方法，如果有传参也需要constructor-arg进行传值<bean id="userDao1" class="factory.MyBeanFactory1" factory-method="userDao"></bean>主函数调用public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Object useDao1 = applicationContext.getBean("userDao1"); System.out.println(useDao1); }执行结果org.example.UserDaoImpl@159f197实例工厂方法化Bean：创建一个方法public class MyBeanFactory2 { public UserDao userDao(){ return new UserDaoImpl(); } }beans.xml中配置该静态方法对bean，并且再次配置一个bean指向该bean，并且使用方法，如果有传参也需要constructor-arg进行传值 <bean id="myBeanFactory2" class="factory.MyBeanFactory2"></bean> <bean id="userDao2" factory-bean="myBeanFactory2" factory-method="userDao"></bean>主函数执行 public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Object userDao2 = applicationContext.getBean("userDao2"); System.out.println(userDao2); }结果输出org.example.UserDaoImpl@51e5fc98实现FactoryBean规范延迟实例化Bean类的接口继承于FactoryBean，在BeanFactory创建时便已经创建实例，但是实例的值并不是真实的对象本身，而是当getBean进行调用的时候，才会将实例对象新建调用getObject方法并且存放到缓存池，然后从缓存池取值从而返回实例对象，如果后续进行重复取值，不会再创建一个新的对象，而是从缓存池取值后直接返回，从而实现FactoryBean规范延迟加载Beanpublic class MyBeanFactory3 implements FactoryBean<UserDao> { @Override public UserDao getObject() throws Exception { return new UserDaoImpl(); } @Override public Class<?> getObjectType() { return null; } }主函数调用public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); Object userDao3 = applicationContext.getBean("userDao3"); Object userDao4 = applicationContext.getBean("userDao3"); System.out.println(userDao3); System.out.println(userDao4); }运行结果org.example.UserDaoImpl@48fa0f47 org.example.UserDaoImpl@48fa0f475.Bean的注入方式 其中，ref是reference的缩写，翻译为参考涉及到意思，用于引入其他Bean的id。value用于注入普通的属性值。6.Bean的依赖注入配置配置注入普通类型的List对象配置接口public interface UserService { public List<String> getStringList(); }配置实现类public class UserServiceImpl implements UserService { //注入List private List<String> stringList; public void setStringList(List<String> stringList) { this.stringList = stringList; } public List<String> getStringList() { return stringList; } }配置Beans.xml文件<bean id="userService" class="org.example.UserServiceImpl"> <property name="stringList"> <value>aaaa</value> <value>bbbb</value> <value>cccc</value> <value>dddd</value> </property> </bean>主函数运行ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); System.out.println(userService.getStringList());运行结果[aaaa, bbbb, cccc, dddd]配置注入引用类型的List对象UserServicelmpl.javapublic List<String> getStringList() { return stringList; } public void setUserDaoList(List<UserDao> userDaoList) { this.userDaoList = userDaoList; }beans.xml需要配置ref或者单独创建bean<bean id="useService1" class="org.example.UserServiceImpl"> <property name="userDaoList"> <bean class="org.example.UserDaoImpl"/> <bean class="org.example.UserDaoImpl"/> <bean class="org.example.UserDaoImpl"/> <bean class="org.example.UserDaoImpl"/> </property> </bean>或者<bean id="userDao1" class="org.example.UserDaoImpl"/> <bean id="userDao2" class="org.example.UserDaoImpl"/> <bean id="userDao3" class="org.example.UserDaoImpl"/> <bean id="userDao4" class="org.example.UserDaoImpl"/> <bean id="useService1" class="org.example.UserServiceImpl"> <property name="userDaoList"> <ref bean="userDao1"/> <ref bean="userDao2"/> <ref bean="userDao3"/> <ref bean="userDao4"/> </property> </bean>配置注入引用类型的set对象配置和List一样，在beans.xml文件中，将list标签改为set配置注入引用类型的map对象配置和List一样，在beans.xml文件中，将list标签改为map，map中标签为entry，key为键名，value为键值，value-ref为引用对象<property name="map"> <entry key="a" value="1111"/> <entry key="b" value="2222"/> </property> <property name="map"> <entry key="a" value-ref="userDao1"/> <entry key="b" value-ref="userDao2"/> </property>
Java BeanFactory与ApplicationContext的关系与继承体系
AI摘要 BeanFactory是Spring的基础Bean工厂，而ApplicationContext是其高级扩展，不仅继承了BeanFactory，还增加了监听、国际化等功能。两者既有继承关系，内部也存在融合。主要区别在于Bean的初始化时机：BeanFactory在首次调用时创建，而ApplicationContext在容器启动时即完成所有Bean的实例化。 此内容根据文章生成，仅用于文章内容的解释与总结 BeanFactory与ApplicationContext的关系BeanFactory是Spring的早期接口，成为Spring的Bean工厂，ApplicationContext是后期更高级接口，称之为Spring容器；ApplicationContext在BeanFactory基础上对功能进行了扩展，例如：监听功能、国际化功能等。BeanFactory的API更偏向于底层，ApplicationContext的API大多数是对这些底层API的封装Bean创建的主要逻辑和功能都被封装在BeanFactory中，ApplicationContext不仅继承了BeanFactory，而且ApplicationContext内部还维护着BeanFactory的引用，所以ApplicationContext与BeanFactory既有继承关系，又有融合关系Bean的初始化时机不同，原始BeanFactory是在首次调用getBean时才进行Bean的创建，而ApplicationContext则是配置文件加载，容器一创建就将Bean都实例化初始化好BeanFactorypublic static void main(String[] args) { // 创建工厂对象 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 创建一个读取器（xml文件） XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); // 读取配置文件给工厂 reader.loadBeanDefinitions("beans.xml"); // 根据id获取bean实例对象，Bean在此时创建对象 UserService userService = (UserService) beanFactory.getBean("userService"); System.out.println(userService); }ApplicationContextpublic static void main(String[] args) { // 读取配置文件的时候便已经实例化初始化完成 ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); System.out.println(userService); }BeanFactory与ApplicationContext的继承体系BeanFactor的继承体系BeanFactory是核心接口，项目运行过程中肯定有具体实现参与，这个具体实现就是DefaultListtableBeanFactory，而ApplicationContext内部维护的BeanFactory的实现类也是它ApplicationContext的继承体系只在Spring基础环境下，即只导入spring-context坐标时，此时ApplicationContext的继承体系 只在Spring基础环境下，常用的三个ApplicationContext作用如下：
AI摘要 ApplicationContext是Spring的核心容器，封装并扩展了BeanFactory的功能，提供了更强大的特性。开发中常使用ClassPathXmlApplicationContext加载配置文件，通过getBean方法即可轻松获取容器中的Bean对象，实现依赖注入与管理。 此内容根据文章生成，仅用于文章内容的解释与总结 Java ApplicationContext快速入门ApplicationContext成为Spring容器，内部封装了BeanFactory，笔BeanFactory功能更丰富更强大，使用ApplicationContext进行开发式，xml配置文件的名称习惯写成applicationContent.xml1.使用ApplicationContext调用BeanFactory基础配置可看上一篇文章 点我跳转public static void main(String[] args) { ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) applicationContext.getBean("userService"); System.out.println(userService); }运行结果：BeanFactory去调用该方法 从容器中获得userDao设置到此处org.example.UserDaoImpl@1e730495 org.example.UserServiceImpl@318ba8c8
AI摘要 本文介绍了Java BeanFactory实现IoC与DI的基本流程。通过配置Maven依赖、定义接口与实现类，利用XML配置文件管理Bean。文章展示了如何使用DefaultListableBeanFactory加载配置，并通过XmlBeanDefinitionReader实现对象的创建与依赖注入，完成Spring容器的基础应用。 此内容根据文章生成，仅用于文章内容的解释与总结 Java BeanFactory快速入门Ioc思想实现1.创建普通的Maven项目2.在pom.xml文件中的project标签内导入Spring的jar包<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> ...... <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.7</version> </dependency> </dependencies> </project>3.创建UserService接口4.创建UserServiceImpl类，并且继承UserService接口5.在resources中创建beans.xml文件，并且配置bean <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userService" class="org.example.UserServiceImpl"></bean> </beans>6.主函数运行 public static void main(String[] args) { // 创建工厂对象 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 创建一个读取器（xml文件） XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); // 读取配置文件给工厂 reader.loadBeanDefinitions("beans.xml"); // 根据id获取bean实例对象 UserService userService = (UserService) beanFactory.getBean("userService"); System.out.println(userService); }DI思想实现，依赖注入1.创建UserDao接口和UserDaoIpml类，类继承UserDao接口2.在UserServiceImpl类中新建一个set方法，用于接受设置注入的对象 public class UserServiceImpl implements UserService{ // BeanFactory去调用该方法 从容器中获得userDao设置到此处 public void setUserDao(UserDao userDao){ System.out.println("BeanFactory去调用该方法 从容器中获得userDao设置到此处" + userDao); } }3.配置beans.xml文件，在bean标签中添加property标签实现依赖注入 <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="userService" class="org.example.UserServiceImpl"> <property name="userDao" ref="userDao"></property> </bean> <bean id="userDao" class="org.example.UserDaoImpl"></bean> </beans>4.主函数调用，完成依赖注入 // 创建工厂对象 DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory(); // 创建一个读取器（xml文件） XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory); // 读取配置文件给工厂 reader.loadBeanDefinitions("beans.xml"); // 根据id获取bean实例对象 UserService userService = (UserService) beanFactory.getBean("userService"); System.out.println(userService);BeanFactory去调用该方法 从容器中获得userDao设置到此处org.example.UserDaoImpl@49c43f4e org.example.UserServiceImpl@290dbf45