试读Spring源码(三)根据Class获取Bean----getBean(Class<T> requiredType)

根据给定类型,获取Bean的具体实现是在DefaultListableBeanFactory类下的<T> T getBean(Class<T> requiredType) throws BeansException方法。其具体实现叙述如下。

调用resolveBean方法,该方法调用resolveNamedBean方法获取到封装了该类型Bean的NamedBeanHolder,如果获取为空,则调用其父BeanFactory获取Bean。

进入resolveNamedBean方法,该方法在首先获取所有类型为指定Class类型的Bean Name。如果获取的Bean Name 数量刚好为1一个,则创建一个NamedBeanHolder,包含该Bean Name和Bean实例,然后返回。如果获取的数量大于1,先实例化所有获取到的Bean,然后通过determinePrimaryCandidate 方法获取属性primary为true的Bean,如果有多个Bean的primary的属性为true,则抛出异常。如果不存在任何一个Bean的primary为true,则通过OrderComparator 比较器来获取Bean的优先级,如果存在多个Bean优先级相同,也抛出异常。

从getBean进入到doGetBean方法,该方法是从BeanFactory创建或者返回已存在Bean的实例。首先通过transformedBeanName方法获取Bean Id。从这个方法上看,Spring应该是允许为别名取别名。获取到Bean Id后先判断是否已存在创建好的单例。如果不存在创建好的单例,且BeanFactory不包含该Bean Id的BeanDefinition,且存在父BeanFactory,则调用父BeanFactory的getBean方法获取Bean。当不符合上述条件,则开始创建Bean的实例。

创建Bean的实例时,先通过getMergedLocalBeanDefinition获取到RootBeanDefinition。合并BeanDefinition是前面初始化时加载好的BeanDefinition中复制一份。如果Bean存在parent definition,就根据parent definition创建一个实例,然后覆盖。当有子孙链的时候将递归调用。获取到BeanDefinition后,根据获取到的BeanDefinition取到该Bean的依赖dependsOn,在将依赖关系注册到BeanFactory后,同样采用递归调用getBean方式获取依赖Bean。接下来判断Bean是否为单例,将采用不同的实例化方法。

当Bean为单例时,会调用getSingleton方法,来获取Bean实例。该方法先判断单例是否存在,如不存在,则开始创建该单例,先做准备工作,将其添加到singletonsCurrentlyInCreation,表示该单例正在创建,避免重复创建,然后调用ObjectFactory的getObject方法,将实例的实现移交给ObjectFactory接口,方便扩展。获取到单例后,将其移除singletonsCurrentlyInCreation,然后将其添加到singletonObjects和registeredSingletons中。

进入创建单例的ObjectFactory实现方法createBean。该方法实现了一个单例创建的完整过程,包括解决单例所属类的加载,单例的实例化,单例属性的赋值或者注入,以及在Spring中创建的生命周期相关的接口的调用。首先通过resolveBeanClass方法加载单例的类对象,并将其设置到BeanDefinition中。然后调用resolveBeforeInstantiation方法,这个方法按照注释,是说给BeanPostProcessors一个机会返回一个代理对象,进到方法里可以看到,如果存在InstantiationAwareBeanPostProcessor处理器,且能够实现对需要获取的Bean实例化,则对该处理器返回的对象调用已注册在BeanFactory的后置处理器,然后就返回,不再对该Bean做其他的处理,也就是将Bean的实例,完全交给了用户自定义的处理器。在没有返回代理对象时,Spring将通过doCreateBean对Bean做实例化。

doCreateBean实例化时,首先通过createBeanInstance方法,采用策略模式,生成包含实例Bean的BeanWrapper实例。其中包含的策略,就是在配置文件配置的生成实例的方式,如工厂方法factory method,构造器constructor autowiring, 或者是其他简单的实例化(没有配置factory-method,也没有配置构造器)。接下来,如果定义有MergedBeanDefinitionPostProcessor处理器,这个节点将会调用。然后在对Bean定义的属性进行计算之前,还将调用InstantiationAwareBeanPostProcessor处理器来对Bean进行处理,这里注释是可用于支持属性注入的方式,这个没懂。后面就是对Bean属性的计算,然后将其设置到Bean实例中。

执行initializeBean方法,处理Bean在Spring的生命周期。这里判断Bean是否实现了相应的事件接口,如BeanNameAware,BeanClassLoaderAware,BeanFactoryAware,这里会调用并注入相应的对象。然后对Bean调用已注册的BeanPostProcessor的postProcessBeforeInitialization方法。执行完后将执行配置里的init方法,如果Bean还实现了InitializingBean接口,这里还将先执行接口里的afterPropertiesSet方法。这样,Bean在Spring的一个创建周期就走完了。

当Bean为多例时,调用过程也类似,就不再赘述。

<think>嗯,用户导入了Spring Context和AspectJ Weaver的依赖,但没出现Spring Config的问题。首先,我需要理清楚这两个依赖的作用。Spring Context是Spring框架的核心,提供IoC和依赖注入功能,而AspectJ Weaver用于支持AOP,比如切面编程。 用户提到“没有出现Spring Config”,可能是指在IDE里没有自动生成配置,或者在项目结构中找不到相关配置。常见的情况是,用户可能期望Spring自动生成配置文件,但实际上需要手动创建。比如,Spring的XML配置文件(如applicationContext.xml)或Java配置类(带@Configuration的类)需要用户自己创建,Spring不会自动生成。 另外,检查依赖是否正确引入。用户提供的Maven依赖版本是5.1.11.RELEASE和AspectJ 1.9.6,可能存在版本兼容性问题吗?不过这两个版本通常是兼容的,但需要确认是否有冲突。用户是否执行了Maven的重新导入?有时候依赖没下载完全会导致问题。 还有,是否缺少必要的配置?比如,如果使用注解驱动,需要在配置类上添加@EnableAspectJAutoProxy,或者在XML中配置<aop:aspectj-autoproxy/>。如果用户没有正确配置这些,即使有AspectJ Weaver的依赖,AOP也不会生效,导致Spring Config不出现。 另外,项目结构是否正确?比如,配置文件是否放在src/main/resources目录下,或者配置类是否在组件扫描的包路径下。如果配置类不在扫描范围内,Spring不会加载它,导致配置无效。 用户可能混淆了依赖引入和配置创建。添加依赖只是提供了库的支持,但具体的配置需要用户自行设置。比如,使用Java配置或XML配置来定义Bean和切面。如果用户没有创建这些配置,Spring自然不会自动生成。 还有可能用户期望IDE的某些功能,比如Spring Tools Suite的仪表盘或配置支持,但普通项目可能需要手动启用Spring插件或配置。或者,用户可能没有正确设置Spring Facet,导致IDE没有识别到Spring项目结构。 最后,是否需要检查构建工具的输出,确认依赖是否被正确下载,没有出现错误或冲突。比如,Maven的pom.xml是否正确,依赖是否下载到本地仓库,是否存在网络问题导致依赖下载失败。</think>你遇到的问题可能有以下几个原因,以下从依赖作用和配置方式逐步分析: 1. **依赖作用分析** - `spring-context`: 提供Spring核心容器功能(IoC/DI)和基础注解支持 $$ \text{Spring Context} \supset \{ \text{@Component, @Autowired, @Configuration} \} $$ - `aspectjweaver`: 提供AspectJ切面织入能力(配合`@Aspect`使用) 2. **未出现Spring Config的可能原因** **情况一:未主动创建配置文件** - 需要手动创建以下两种配置之一: - **XML配置**:`src/main/resources/applicationContext.xml` ```xml <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="..."> <context:component-scan base-package="com.example"/> <aop:aspectj-autoproxy/> </beans> ``` - **Java配置类**:`@Configuration`标注的类 ```java @Configuration @ComponentScan("com.example") @EnableAspectJAutoProxy public class AppConfig {} ``` **情况二:配置未被正确加载** - **XML配置需要初始化容器**: ```java ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); ``` - **Java配置需要初始化容器**: ```java AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); ``` 3. **验证步骤** ```mermaid graph TD A[检查依赖] -->|mvn dependency:tree| B[确认spring-conject存在] B --> C[检查配置文件位置] C --> D[确认是否启用组件扫描] D --> E[验证AOP代理是否启用] ``` 4. **典型成功案例** ```java // 定义切面 @Aspect @Component public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))") public void logBefore(JoinPoint joinPoint) { System.out.println("方法执行: " + joinPoint.getSignature()); } } // 主程序 public class MainApp { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class); MyService service = ctx.getBean(MyService.class); service.execute(); } } ``` 5. **版本兼容性建议** - Spring 5.1.x 推荐配合 AspectJ 1.9.x 使用 - 若需使用最新特性,可升级至: ```xml <version>5.3.27</version> <!-- spring-context --> <version>1.9.19</version> <!-- aspectjweaver --> ``` 请根据实际项目结构检查配置文件位置和加载方式,若仍无法解决建议提供具体错误日志。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值