项目启动时候spring是如何加载和实例化各类的

Spring实例化详解

1.对于注解为默认的,也就是@score不写的,默认是单例的类,这些类在项目启动的时候会依次被加载并被实例化。默认调用的是无参数的构造器。

2.而对于注解是prototype类型的,即@Scope("prototype"),在首次被用到的时候加载。

 

转载于:https://www.cnblogs.com/roy-blog/p/6495393.html

<think> 我们正在讨论一个关于Spring框架如何加载代码的实现原理的问题。用户希望了解Spring是如何将代码(特别是Bean的定义实现)加载到容器中的。根据提供的引用,我们可以从几个关键点来解析: 1. **动态代理机制**:引用[1][2]都提到了Spring使用动态代理来实现事务管理。动态代理是Spring AOP的核心,它允许Spring在运行时创建代理对象,从而在方法调用前后插入额外的逻辑(如事务管理)。具体来说,通过`InvocationHandler`的`invoke`方法,Spring可以在目标方法执行前后添加事务管理的代码。 2. **Bean的加载容器管理**:引用[4]提到,Spring容器通过一个Map(键为字符串,值为对象)来存放加载的对象。当获取对象时,通过键(通常是Bean的名称)来获取对应的对象。这表明Spring的IoC容器本质上是一个对象注册表,负责管理Bean的生命周期。 3. **懒加载机制**:引用[3]提到了懒加载。在Spring中,默认情况下Bean是在容器启动时创建的(饿汉式),但也可以配置为懒加载(懒汉式),即第一次使用时才创建。对于存在循环依赖的Bean,Spring会使用代理对象作为占位符,直到实际需要时才初始化真正的Bean。 4. **外部配置的加载**:引用[5]提到,可以使用`@ImportResource`注解来加载外部的XML配置文件,这使得Spring Boot应用可以灵活地结合注解配置传统的XML配置。 综合以上引用,我们可以将Spring加载代码的原理归纳为以下几个步骤: 1. **配置元数据的读取**:Spring容器启动时,会读取配置元数据(可以是XML、注解或Java配置)。这些配置定义了如何创建组装Bean。 2. **Bean定义的注册**:容器将读取到的Bean定义(BeanDefinition)注册到一个内部注册表中(如`BeanDefinitionRegistry`)。每个Bean定义包含了创建Bean所需的信息(如名、作用域、依赖关系等)。 3. **Bean的实例化**:容器遍历注册表中的Bean定义,根据配置(懒加载或非懒加载)决定何时实例化Bean。实例化通常通过反射调用构造函数完成。 4. **依赖注入**:容器解析Bean之间的依赖关系,并通过反射或setter方法将依赖注入到Bean中。 5. **AOP代理的创建**:如果Bean需要被增强(如事务管理),Spring会使用动态代理(JDK动态代理或CGLIB)创建代理对象。代理对象在方法调用前后执行额外的逻辑(如开启事务、提交事务等)。 6. **Bean的初始化**:容器调用初始化回调方法(如`InitializingBean`的`afterPropertiesSet`方法或自定义的`init-method`),完成Bean的初始化。 7. **Bean的使用销毁**:初始化后的Bean被放入容器中(通常是单例池),供其他Bean或应用使用。当容器关闭时,会调用销毁方法(如`DisposableBean`的`destroy`方法或自定义的`destroy-method`)。 对于动态代理部分,我们可以参考引用[2]中的代码示例: ```java public class TxHandler implements InvocationHandler { private Object originalObject; public Object bind(Object obj) { this.originalObject = obj; return Proxy.newProxyInstance( obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this ); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object result = null; if (!method.getName().startsWith("save")) { UserTransaction tx = null; try { tx = (UserTransaction) (new InitialContext().lookup("java/tx")); result = method.invoke(originalObject, args); tx.commit(); } catch (Exception ex) { if (null != tx) { try { tx.rollback(); } catch (Exception e) { } } } } else { result = method.invoke(originalObject, args); } return result; } } ``` 这段代码展示了如何通过动态代理在方法调用前后添加事务管理代码。Spring的事务管理就是基于似机制实现的。 另外,关于懒加载循环引用,引用[3]提到,即使配置了懒加载Spring也可能创建代理对象来解决循环依赖问题。这意味着在循环引用中,一个Bean可能持有另一个Bean的代理对象(而不是实际对象),直到实际使用时才初始化真正的对象。 总结:Spring加载代码的核心原理是通过IoC容器管理Bean的生命周期(包括实例化、依赖注入、初始化等),并通过动态代理实现AOP(如事务管理)。容器底层使用Map结构存储Bean,并通过配置元数据(XML、注解等)来指导容器的行为。 现在,我们可以按照用户的要求,以清晰的结构来组织回答,并在适当位置添加引用标记。同时,生成相关问题。 </think> ### Spring 加载代码的实现原理 Spring 框架加载代码的核心是通过 **IoC 容器**(控制反转容器)实现,其原理可分解为以下关键步骤: #### 1. **配置元数据加载** Spring 首先读取各类配置源: - 注解配置(`@Component`, `@Service` 等) - XML 配置文件(`<bean>` 定义) - Java 配置(`@Configuration`) - 外部属性文件(`@PropertySource`) 这些配置定义了对象的**依赖关系****初始化规则**,构成 Bean 的元数据模型 `BeanDefinition`[^4]。 #### 2. **BeanDefinition 注册 容器解析配置后,将所有 Bean 定义注册到 `BeanDefinitionRegistry`: ```java // 伪代码:Spring 内部注册逻辑 Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(); beanDefinitionMap.put("serviceA", new RootBeanDefinition(ServiceA.class)); beanDefinitionMap.put("serviceB", new RootBeanDefinition(ServiceB.class)); ``` 此阶段完成**名→定义**的映射,但尚未实例化对象[^4]。 #### 3. **Bean 实例化与依赖注入 当调用 `getBean()` 时触发实例化: - **实例化**:通过反射调用构造函数 `clazz.newInstance()` - **依赖注入**:递归解析依赖关系 ```java // 伪代码:依赖注入过程 for (Field field : bean.getClass().getDeclaredFields()) { if (field.isAnnotationPresent(Autowired.class)) { Object dependency = getBean(field.getType()); // 递归获取依赖 field.setAccessible(true); field.set(bean, dependency); // 注入依赖 } } ``` #### 4. **AOP 动态代理(关键增强) 对于需要事务管理/AOP 的 Bean,Spring 创建**动态代理对象**: ```java // 基于引用[2]的代理实现增强版 public Object invoke(Object proxy, Method method, Object[] args) { if (isTransactional(method)) { // 检查事务注解 startTransaction(); // 前置增强:开启事务 Object result = method.invoke(target, args); // 执行原方法 commitTransaction(); // 后置增强:提交事务 return result; } return method.invoke(target, args); // 无增强直接执行 } ``` 代理对象在**方法调用层面**插入横切逻辑(如事务管理)[^1][^2]。 #### 5. **懒加载优化(Lazy Initialization) 对于 `@Lazy` 注解的 Bean: 1. 初始化时仅创建**代理占位符** 2. 首次方法调用时触发真实对象初始化 3. 代理对象自动替换为实际 Bean ```mermaid graph LR A[调用懒加载Bean方法] --> B(代理对象拦截) B --> C{是否已初始化?} C -- 否 --> D[创建真实对象] D --> E[替换代理对象] C -- 是 --> F[直接调用] ``` 此机制解决循环依赖问题,避免启动性能瓶颈[^3]。 #### 6. **外部配置加载扩展 通过 `@ImportResource` 整合遗留配置: ```java @ImportResource(locations = {"classpath:legacy-config.xml"}) @Configuration public class AppConfig { // 将XML配置的Bean纳入容器管理 } ``` 实现**注解配置**与**传统XML**的无缝融合[^5]。 ### 核心设计思想 1. **控制反转(IoC)** 将对象创建的控制权从代码转移到容器 2. **依赖注入(DI)** 通过构造函数/Setter实现解耦,满足依赖关系: $$ \text{BeanA} \xrightarrow{\text{@Autowired}} \text{BeanB} $$ 3. **面向切面编程(AOP)** 通过动态代理实现横切关注点分离,典型应用: - 事务管理 `@Transactional` - 安全校验 `@Secured` - 日志记录 `@Loggable` > Spring 通过组合 **反射机制**、**动态代理**、**元数据建模** **策略模式**,实现了灵活的代码加载架构。容器在启动时构建 Bean 定义图谱,运行时按需实例化并通过代理增强功能,最终提供完整的应用对象上下文[^1][^2][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值