Table of Contents
spring给java开发带来了哪些帮助?why spring?
Spring配置元数据Configuration Metadata
问题1:spring是如何实现发现bean并加入到容器当中的?
问题3:不使用xml,而使用注解@Autowire注入一个bean?spring是如何实现的?
什么是bean的循环依赖?spring 如何解决的循环依赖?
一个spring mvc项目的启动过程是怎样的,spring boot和springmvc的区别?
Spring的一个启动时自动加载的bean,如果去看它的配置和信息
spring给java开发带来了哪些帮助?why spring?
spring带来的帮助非常之多,现在的spring框架可以说是相当的庞大,在spring的官方文档里面,有一个目录,我们可以从这个目录作为出发点。

其中最为核心的就是Core technologies.包括:依赖注入即ioc,事件,资源,i18n国际化,验证,数据绑定,类型转换,SpEL是spring提供的语法,以及AOP。本篇文章将围绕core technologies做介绍。
总结起来,可以从以下几个方面来看。
- 非侵入式:支持基于POJO的编程模式,不强制性的要求实现Spring框架中的接口或继承Spring框架中的类。
- IoC容器:IoC容器帮助应用程序管理对象以及对象之间的依赖关系,对象之间的依赖关系如果发生了改变只需要修改配置文件而不是修改代码,因为代码的修改可能意味着项目的重新构建和完整的回归测试。有了IoC容器,程序员再也不需要自己编写工厂、单例,这一点特别符合Spring的精神"不要重复的发明轮子"。
- AOP(面向切面编程):将所有的横切关注功能封装到切面(aspect)中,通过配置的方式将横切关注功能动态添加到目标代码上,进一步实现了业务逻辑和系统服务之间的分离。另一方面,有了AOP程序员可以省去很多自己写代理类的工作。
- MVC:Spring的MVC框架是非常优秀的,从各个方面都可以甩Struts 2几条街,为Web表示层提供了更好的解决方案。
- 事务管理:Spring以宽广的胸怀接纳多种持久层技术,并且为其提供了声明式的事务管理,在不需要任何一行代码的情况下就能够完成事务管理。
- 其他:选择Spring框架的原因还远不止于此,Spring为Java企业级开发提供了一站式选择,你可以在需要的时候使用它的部分和全部,更重要的是,你甚至可以在感觉不到Spring存在的情况下,在你的项目中使用Spring提供的各种优秀的功能。
spring IoC
IoC即Inversion of control,直译过来就是控制反转,它的意思是将对象,以及对象之间的引用关系,交给容器管理。从spring的官方文档来看,我们在说ioc的时候后面其实漏掉了一个单词:container。spring core的第一部分的题目就是:The IOC container。即IOC容器的意思。这一部分的内容其实官方文档讲的是最清楚的。因此我这里只列出最重要的核心内容。
org.springframework.context.ApplicationContext接口表示Spring IoC容器,负责实例化,配置和组装bean。 容器通过读取配置元数据获取有关要实例化,配置和组装的对象的指令。 配置元数据以XML,Java注释或Java代码表示。 它允许表达组成应用程序的对象以及这些对象之间丰富的相互依赖性。
下图显示了Spring如何工作的高级视图。 应用程序类与配置元数据相结合,以便在创建和初始化ApplicationContext之后,可以拥有一个完全配置且可执行的系统或应用程序:

IoC是spring的核心,贯穿始终。所谓IoC,对于spring框架来说,就是由spring来负责控制对象的生命周期和对象间的关系.
Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。
Spring配置元数据Configuration Metadata
Spring IoC容器的工作是要基于使用配置的元数据。 配置元数据表示我们作为应用程序开发人员如何告诉Spring容器在应用程序中实例化,配置和组装对象。
传统上,spring的配置元数据以简单直观的XML格式提供。相较于其他配置的方式,xml格式是最直观最能反映逻辑的方式
Spring的配置由容器管理的至少一个且通常不止一个的bean定义组成。 基于XML的配置元数据将这些bean配置为顶层<beans />元素内的<bean />元素。 Java配置通常在@Configuration类中使用@ Bean 去注释方法。
这些bean定义对应于构成应用程序的实际对象。 通常,您定义服务层对象,数据访问对象(DAO),表示对象(如Struts Action实例),基础结构对象(如Hibernate SessionFactories,JMS队列等)。 通常,不会在容器中配置细粒度域对象,因为创建和加载域对象通常由DAO和业务逻辑负责。 但是,我们可以使用Spring与AspectJ的集成来配置在IoC容器控制之外创建的对象
以下示例显示了基于XML的配置元数据的基本结构:
<?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="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<bean id="..." class="...">
<!-- collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions go here -->
</beans>
id属性的值指的是协作对象。 在此示例中未显示用于引用协作对象的XML
实例化IOC Container
我们传给ApplicationContext构造函数的位置路径是资源字符串,它允许容器从各种外部资源(如本地文件系统,Java CLASSPATH等)加载配置元数据。说白了就是告诉容器加载配置文件的位置
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml", "daos.xml");
以下示例显示了服务层(services.xml)配置文件:
<?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">
<!-- services -->
<bean id="petStore" class="org.springframework.samples.jpetstore.services.PetStoreServiceImpl">
<property name="accountDao" ref="accountDao"/>
<property name="itemDao" ref="itemDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for services go here -->
</beans>
以下示例显示了数据访问层daos.xml文件:
<?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="accountDao"
class="org.springframework.samples.jpetstore.dao.jpa.JpaAccountDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<bean id="itemDao" class="org.springframework.samples.jpetstore.dao.jpa.JpaItemDao">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<!-- more bean definitions for data access objects go here -->
</beans>
在前面的示例中,服务层由PetStoreServiceImpl类和两个类型为JpaAccountDao和JpaItemDao的数据访问对象组成(基于JPA对象关系映射标准)。 属性name元素引用JavaBean属性的名称,ref元素引用另一个bean定义的名称。 id和ref元素之间的这种联系表达了协作对象之间的依赖关系。
关于IOC中的bean
Spring IoC容器管理一个或多个bean。 这些bean是使用开发人员提供给容器的配置元数据创建的(例如,以XML <bean />定义的形式)。
在容器本身内,这些bean定义表示为BeanDefinition对象,其中包含(以及其他信息)以下元数据:
- 包限定的类名:通常是定义的bean的实际实现类。
- Bean行为配置元素,说明bean在容器中的行为方式(范围,生命周期回调等)。
- 引用bean执行其工作所需的其他bean。 这些引用也称为协作或依赖项。
- 要在新创建的对象中设置的其他配置设置 - 例如,池的大小限制或在管理连接池的Bean中使用的连接数。
实例化bean
bean定义本质上是用于创建一个或多个对象的一种"配方"。 容器在被询问时查看命名bean的"配方",并使用由该bean定义封装的配置元数据来创建(或获取)实际对象。
如果使用基于XML的配置元数据,则指定要在<bean />元素的class属性中实例化的对象的类型(或类)。 此类属性(在内部,是BeanDefinition实例上的Class属性)通常是必需的。我们可以使用以下两种方法之一来使用Class属性:
- 通常,在容器本身通过反向调用其构造函数直接创建bean的情况下指定要构造的bean类,类似于使用new运算符的Java代码。
- 要指定包含为创建对象而调用的静态工厂方法的实际类,在不太常见的情况下,容器在类上调用静态工厂方法来创建bean。 从静态工厂方法的调用返回的对象类型可以完全是同一个类或另一个类。
实例化bean主要有以下几种方法
- 使用构造方法实例化
- 使用静态工厂方法实例化
- 使用工厂方法实例化
基于注解的容器配置
问题:注释是否比XML配置更好?
基于注释的配置是否比基于XML的配置更好呢。事实上这个问题并没有一个标准的答案,而是应该视情况而定。每种方法都有其优点和缺点,通常,由开发人员决定哪种策略更适合他们。注释在其声明中提供了大量上下文,从而导致更短更简洁的配置。但是,XML擅长在不触及源代码或重新编译它们的情况下连接组件。一些开发人员更喜欢配置和源代码在一个地方,而另一些开发人员则认为带有注释的类不再是POJO,还有一种观点认为基于xml的配置会变得分散且难以控制。
无论选择如何,Spring都可以支持两种风格,甚至可以将它们混合在一起使用。值得指出的是,如果使用JavaConfig,Spring允许以非侵入方式使用注释,而无需触及目标组件源代码,
基于注释的配置提供了XML配置的方案,该配置依赖于字节码元数据来连接组件而不是声明。
而使用注释的话,则开发人员需要使用XML来描述bean连接,而是通过在相关的类,方法或字段声明上使用注释将配置移动到组件类本身。将BeanPostProcessor与注释结合使用是扩展Spring IoC容器的常用方法。例如,Spring 2.0引入了使用@Required注释强制执行所需属性的可能性。 Spring 2.5使得有可能采用相同的通用方法来驱动Spring的依赖注入。从本质上讲,@ Autowired注释提供的功能与自动装配协作者中描述的相同,但具有更细粒度的控制和更广泛的适用性。 Spring 2.5还增加了对JSR-250注释的支持,例如@ PostConstruct和@PreDestroy。 Spring 3.0增加了对javax.inject包中包含的JSR-330(Java的依赖注入)注释的支持,例如@Inject和@Named。
关于这些注解的用法请参考另一篇博客:Spring重要注解用法分析
什么是DI(依赖注入)?
IoC的一个重点是在系统运行中,动态的向某个对象提供它所需要的其他对象。这一点是通过DI(Dependency Injection,依赖注入)来实现的。比如对象A需要操作数据库,以前我们总是要在A中自己编写代码来获得一个Connection对象,有了 spring我们就只需要告诉spring,A中需要一个Connection,至于这个Connection怎么构造,何时构造,A不需要知道。在系统运行时,spring会在适当的时候制造一个Connection,然后像打针一样,注射到A当中,这样就完成了对各个对象之间关系的控制。A需要依赖 Connection才能正常运行,而这个Connection是由spring注入到A中的,依赖注入的名字就这么来的。那么DI是如何实现的呢? Java 1.3之后一个重要特征是反射(reflection),它允许程序在运行的时候动态的生成对象、执行对象的方法、改变对象的属性,spring就是通过反射来实现注入的.
问题1:spring是如何实现发现bean并加入到容器当中的?
先考虑使用xml文件定义bean的情况。
spring解析bean加载到容器当中主要有以下几步:
- 在xml文件里定义bean的信息
- 使用dom4j技术解析xml文件->拿到类名->使用反射技术创建类对应的class对象
- 使用反射技术-根据类对象创建实例对象
- 设计模式的工厂模式
从整体来看,解析和创建类对象的代码是放在一个统一的地方管理的,在这里使用了工厂模式。
当我们改变对象时,只需要xml文件作出适当的改变就好了,剩余都交给了spring处理,即交给了工厂处理。好处是:
不适用xml是用注解定义一个bean,是怎么实现的了,下面的问题3回答了这个问题。
问题2:spring是如何通过反射实现依赖注入的?
我们来看下面的代码
public class MainApp {
public static void main(String[] args) {
ApplicationContext context =
new ClassPathXmlApplicationContext("BeansIOCConstructor.xml");
TextEditor te = (TextEditor) context.getBean("textEditor");
te.spellCheck();
}
}
在这里xml文件里面到底是setter注入还是构造方法注入,我们根本就无需关系,这些类怎么定义的我们也不去关心,就只看这个运行类。这个运行类不就是想做一件事情:调用TextEditor 这个类的spellCheck方法吗?那自然我们就需要这个类的一个砬对象,既然spring容器帮我们管理了这个对象,于是我们就不通过关键字new,而是通过spring去获得这个多谢,怎么获得的呢?在xml文件里必然定义了这个类的相关信息,其中class的全限定名是必须定义的,为什么要定义全限定名,自然就是因为spring要帮我们加载这个类,只能是利用反射机制,根据这个类的全限定名称,才能够做到动态的去加载这个类(联系Class.forName方法理解),然后加载了之后,通过这里的getBean方法去获得这个类的对象,就可以去调用它的方法了。至于别的可以配的参数,我们现在根本无需关心。
以上就是spring通过反射实现依赖注入的思想。
问题3:不使用xml,而使用注解@Autowire注入一个bean?spring是如何实现的?
首先,要回答这个问题必须弄明白的是java是如何解析注解的。
我们来看一下一个注解的定义是怎样的:
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
/**
* Declares whether the annotated dependency is required.
* <p>Defaults to {@code true}.
*/
boolean required() default true;
}
以Autowired为例,可以发现,事实上每一个注解本质上都是一个接口,当我们在某一个类当中用到这个注解的时候,就可以通过反射知道是哪个类用了这个注解。也就能拿到这个类的类名,然后就可以根据类名使用反射机制创建对象。与xml的方式就是一样了。大致步骤如下:
- 利用反射机制获取一个类的Class对象
- 通过这个class对象可以去获取他的每一个字段Field
- Field类提供了方法getDeclaredAnnotations来获取这个一个字段的所有注解
大致代码如下:
Class<?> cl = Class.forName(className);
for(Field field : cl.getDeclaredFields()) {
//获取字段上的注解
Annotation[] anns = field.getDeclaredAnnotations();
...
}
关于注解的有效周期:
各种注释之间的第一个主要区别是,它们是在编译时使用,然后被丢弃(如@Override),还是被放在编译的类文件中,并在运行时可用(如Spring的@Component)。这是由注释的“@Retention”策略决定的。如果您正在编写自己的注释,则需要决定该注释在运行时(可能用于自动配置)还是仅在编译时(用于检查或代码生成)有用。
当用注释编译代码时,编译器看到注释就像看到源元素上的其他修饰符一样,比如访问修饰符(public/private)或.。当遇到注释时,它运行一个注释处理器,就像一个插件类,表示对特定的注释感兴趣。注释处理器通常使用反射API来检查正在编译的元素,并且可以简单地对它们执行检查、修改它们或生成要编译的新代码。@Override是一个示例;它使用反射API来确保能够在其中一个超类中找到方法签名的匹配,如果不能,则使用@Override会导致编译错误。
总结起来,无论使用注解还是使用xml,反射都是关键的实现技术。
更完整的介绍请参考博客[spring] 注解@Autowired是如何实现的.
问题四:依赖注入时,被注入的对象有多个参数,会怎么样?
todo
spring aop
spring aop是spring核心技术的一部分,可谓重中之重。spring aop实现核心技术:反射。实现方式:代理,包括有jdk动态代理和cglib动态代理两种方式。
- jdk动态代理
- cglib动态代理
关于这两种代理模式的实现方式,专门放在了代理模式与AOP这篇博客里面。
此外aop的主要使用场景还有下面这些:
| Authentication | 权限 |
| Caching | 缓存 |
| Error handling | 错误处理 |
| Lazy loading | 懒加载 |
| Debugging | 调试 |
| logging, tracing, profiling and monitoring | 记录跟踪 优化 校准 |
| Performance optimization | 性能优化 |
| Persistence | 持久化 |
| Resource pooling | 资源池 |
| Synchronization | 同步 |
| Transactions | 事务 |
| Context passing | 内容传递 |
什么是bean的循环依赖?spring 如何解决的循环依赖?
循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方,示意图如下:

值得注意的是,我们即便不使用spring,自己管理对象之间的关系,仍然会遇到这个问题。因为我们使用了spring来管理对象,spring必然需要去考虑这个问题。
另外,这里的循环依赖,要和循环调用区分开来,循环调用是一个死循环,java里面一个很著名的循环调用死循环就是HashMap在并发下可能出现的环装链表。
代码如下:
public class TestA {
// TestA依赖TestB
private TestB testB;
public TestA(TestB testB) {
this.testB = testB;
}
public TestB getTestB() {
return testB;
}
public void setTestB() {
this.testB = testB;
}
}
public class TestB {
// TestB依赖TestC
private TestC testC;
public TestB(TestC testC) {
this.testC = testC;
}
public TestC getTestC() {
return testC;
}
public void setTestC() {
this.testC = testC;
}
}
public class TestC {
// TestC依赖TestA
private TestA testA;
public TestC(TestA testA) {
this.testA = testA;
}
public TestA getTestA() {
return testA;
}
public void setTestA() {
this.testA = testA;
}
}
Spring中循环依赖场景有:
- 构造器的循环依赖 。
<bean id="testA" class="com.bean.TestA"> <constructor-arg index="0" ref="testB" /> </bean> <bean id="testB" class="com.bean.TestB"> <constructor-arg index="0" ref="testC" /> </bean> <bean id="testC" class="com.bean.TestC"> <constructor-arg index="0" ref="testA" /> </bean>解决方法:spring无法解决这种问题,为何?只能抛出BeanCurrentlyInCreationException异常来终止该依赖。
具体的处理步骤:
1.Spring将每个正在创建的bean的标识符放在一个池子里
2.如果bean在创建的时候发现自己已经存在于这个池子里
3.则抛出异常,中断循环依赖。 例如:Spring容器先创建单例A,A依赖B,然后将A放在“当前创建Bean池”中,此时创建B,B依赖C ,然后将B放在“当前创建Bean池”中,此时创建C,C又依赖A, 但是,此时A已经在池中,所以会报错,,因为在池中的Bean都是未初始化完的,所以会依赖错误 ,(初始化完的Bean会从池中移除,而现在池中已经有了A,B,C对象处于正在创建的状态,但是C对象又试图去创建A对象,此时,抛出异常)。
- field属性的循环依赖, setter循环依赖
<bean id="testA" class="com.bean.TestA"> <property name="testB" ref="testB" /> </bean> <bean id="testB" class="com.bean.TestB"> <property name="testC" ref="testC" /> </bean> <bean id="testC" class="com.bean.TestC"> <property name="testA" ref="testA" /> </bean>解决方案:
1.spring将已经完成了构造注入但是未完成setter注入的bean暴露出来
2.当进行setter注入时,发现这个需被注入的bean已经被暴露出来(存在该bean的引用),直接注入即可,而不需要再次加载所需的bean(无需再经历从头开始加载一个bean的过程,也就不会报错了)。
Spring先是用构造实例化Bean对象 ,创建成功后,Spring会通过以下代码提前将对象暴露出来,此时的对象A还没有完成属性注入,属于早期对象,此时Spring会将这个实例化结束的对象放到一个Map(缓存)中,并且Spring提供了获取这个未设置属性的实例化对象引用的方法。 结合我们的实例来看,当Spring实例化了A、B、C后,紧接着会去设置对象的属性,此时A依赖B,就会去Map中取出存在里面的单例B对象,以此类推,不会出来循环的问题。
另外,spring解决的setter循环依赖仅仅针对于单例的bean,对于非单例的bean,Spring无法完成依赖注入,因为spring容器不缓存“prototype”作用域的bean,因此无法提前暴露一个创建中的bean,但是对于单例(singleton)的bean,可以通过“setAllowCircularReferences( false );”来禁用循环引用。
怎么检查是否存在循环依赖?
检测循环依赖相对比较容易,Bean在创建的时候可以给该Bean一个标记(如 boolean isCreating = false),如果递归调用回来发现正在创建中(isCreating = true)的话,即说明了循环依赖了.
问题:为什么更推荐使用构造方法一次注入bean?
我构造方法注入好于字段类型的注入的原因主要是以下三点:
1.注入的bean和使用这个bean的类关系清楚,一目了然。在任何其他情况下测试或实例化对象时都必须把所有需要的bean注入才能实例化成功,这避免了我们因为疏忽忘记某一个bean。
2.通过构造方法注入我们的bean可以定义为final的,这有助于提高健壮性和线程安全性,如下代码所示:
private final ClassTest classTest;
public DataMigrationService(ClassTest classTest) {
this.classTest = classTest;
}
问题:为什么final变量注入的bean可以提高健壮性和线程安全性?读者不妨自己思考一下这个问题。
3.在测试的时候我们mock更加方便,可以自己创建需要的bean然后通过构造方法传入即可。
Spring Cloud简介
spring cloud也是spring子项目的其中之一,与spring boot一样,spring boot是为了简化spring自身配置而生的。spring cloud则是专为微服务和分布式系统而设计的。
Spring Cloud为开发人员提供了在分布式系统中快速构建一些常见模式的工具,例如配置管理 configuration management、服务发现 service discovery、断路器、智能路由intelligent routing、微代理micro-proxy、控制总线、一次性令牌、全局锁、领导选举 leadership election、分布式会话,簇状态cluster state。
Spring cloud主要的目标是为以下这些典型的用例提供良好的拆箱即用的体验和可扩展性机制。
- Distributed/versioned configuration
- Service registration and discovery
- Routing
- Service-to-service calls
- Load balancing
- Circuit Breakers
- Global locks
- Leadership election and cluster state
- Distributed messaging
问题
springMVC的执行流程是怎样的
springMVC是由dispatchservlet为核心的分层控制框架。
首先客户端发出一个请求web服务器解析请求url并去匹配dispatchservlet的映射url,如果匹配上就将这个请求放入到dispatchservlet,dispatchservlet根据mapping映射配置去寻找相对应的handel,然后把处理权交给找到的handel,handel封装了处理业务逻辑的代码,当handel处理完后会返回一个逻辑视图modelandview给dispatchservlet,此时的modelandview是一个逻辑视图不是一个正式视图,所以dispatchservlet会通过viewresource视图资源去解析modelandview,然后将解析后的参数放到view中返回到客户端并展现。
一个spring mvc项目的启动过程是怎样的,spring boot和springmvc的区别?
Spring MVC是Spring提供的一个强大而灵活的模块式web框架。通过Dispatcher Servlet, ModelAndView 和 View Resolver,开发web应用变得很容易。
Spring MVC框架提供了开发Web应用的分离方式。通过DispatcherServlet、ModelAndView、View Resolver等简单概念,是Web应用开发变得更加简单。
但是Spring和Spring MVC的众多配置有时却让人望而却步,相信有过Spring MVC开发经验的朋友能深刻体会到这一痛苦。因为即使是开发一个Hello-World的Web应用,都需要我们在pom文件中导入各种依赖,编写web.xml、spring.xml、springmvc.xml配置文件等。特别是需要导入大量的jar包依赖时,我们需要在网上查找各种jar包资源,各个jar间可能存在着各种依赖关系,这时候又得下载其依赖的jar包,有时候jar包间还存在着严格的版本要求,,所以当我们只是想开发一个Hello-World的超简单的Web应用时,却把极大部分的时间在花在了编写配置文件和导入jar包依赖上,极大地影响了我们的开发效率。所以为了简化Spring繁杂的配置,Spring Boot应运而生。正如Spring Boot的名称一样,一键启动,Spring Boot提供了自动配置功能,为我们提供了开箱即用的功能,使我们将重心放在业务逻辑的开发上。
Spring的一个启动时自动加载的bean,如果去看它的配置和信息
去查看源代码肯定是一个大家都可以想到的方式。
还有一个比较好的方式是,可以在代码里注入这个bean,然后去把它的所有信息打印出来,这是一个非常快而且效率高的方式。
参考:https://blog.csdn.net/chejinqiang/article/details/80003868#3849-1524062318691

本文深入探讨了Spring框架的核心——IoC(控制反转)和依赖注入(DI)。首先解释了IoC的概念,强调了它如何通过容器管理对象及对象间的依赖关系。接着详细阐述了Spring配置元数据,包括XML和基于注解的配置。讨论了如何实例化IoC容器,以及bean的创建、依赖关系和循环依赖的处理。文章还涵盖了基于注解的配置和DI的优势与实现方式,以及Spring如何通过反射实现依赖注入。最后,提到了Spring Cloud简介及其在微服务和分布式系统中的作用。
360

被折叠的 条评论
为什么被折叠?



