反射生成对象,spring注入无效

本文探讨了使用反射创建的对象与Spring容器的关系及其影响,特别是Spring注解如@Transactional的失效问题,并提供了一种通过工具类从Spring容器中获取Bean的方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

反射类似于new出来的对象,不在spring容器中,所以spring的注解全都无效,当然包括事物@Transactional!

也可以通过代码的方式从applicationContext中取出需要注入的属性
Service service = (Service) SpringContextUtil.getBean("service");
注意:要放在方法中,不要声明为成员变量,否则启动程序时会实例化失败报异常的

spring配置

<bean id="springContextUtil" class="com.xxx.xxx.xxx.util.SpringContextUtil"/>
放上工具类:
public class SpringContextUtil implements ApplicationContextAware {
	private static ApplicationContext applicationContext; // Spring应用上下文环境

	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		if(SpringContextUtil.applicationContext == null){
			SpringContextUtil.applicationContext  = applicationContext;
		}
	}

	public static ApplicationContext getApplicationContext() {
		return applicationContext;
	}

	public static Object getBean(String name) throws BeansException {
		return applicationContext.getBean(name);
	}

	public static Object getBean(String name, Class requiredType)
			throws BeansException {
		return applicationContext.getBean(name, requiredType);
	}

	public static boolean containsBean(String name) {
		return applicationContext.containsBean(name);
	}

	public static boolean isSingleton(String name)
			throws NoSuchBeanDefinitionException {
		return applicationContext.isSingleton(name);
	}

	public static Class getType(String name)
			throws NoSuchBeanDefinitionException {
		return applicationContext.getType(name);
	}

	public static String[] getAliases(String name)
			throws NoSuchBeanDefinitionException {
		return applicationContext.getAliases(name);
	}
}

<think>我们聚焦于SpringBoot自动配置中反射机制的使用原理。根据引用内容,自动配置的核心是@EnableAutoConfiguration注解(包含在@SpringBootApplication中),其通过反射实现条件化加载配置类。以下是反射在自动配置中的关键应用点:###1.**自动配置类的加载与过滤**SpringBoot启动时通过`SpringFactoriesLoader`加载`META-INF/spring.factories`中注册的自动配置类(如`org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration`)[^3][^4]。这些配置类被加载到内存后,**反射机制**用于:-解析类上的条件注解(如`@ConditionalOnClass`)-动态验证条件是否满足```java//反射验证条件注解的伪代码List<String>autoConfigClasses=loadSpringFactories();//加载配置类名for(StringclassName:autoConfigClasses){Class<?>configClass=Class.forName(className);//反射加载类//检查@ConditionalOnClass注解ConditionalOnClasscond=configClass.getAnnotation(ConditionalOnClass.class);if(cond!=null){for(StringrequiredClass:cond.value()){//反射检查类路径是否存在所需类if(!ClassUtils.isPresent(requiredClass,classLoader)){skipConfiguration(configClass);//条件不满足则跳过break;}}}}```###2.**条件注解的动态评估**条件注解(如`@ConditionalOnMissingBean`)的校验依赖反射:-通过反射检查BeanFactory中是否已存在某类型的Bean-通过反射检查类路径是否存在指定类**示例:`@ConditionalOnClass`的实现核心**```javapublicclassOnClassConditionimplementsCondition{@Overridepublicbooleanmatches(ConditionContextcontext,AnnotatedTypeMetadatametadata){//通过反射获取注解中要求的类名List<String>requiredClasses=metadata.getAnnotations().get(ConditionalOnClass.class).getStringArray("value");//反射检查这些类是否可加载for(StringclassName:requiredClasses){if(!ClassUtils.isPresent(className,context.getClassLoader())){returnfalse;//条件不满足}}returntrue;}}```###3.**配置类的方法解析与Bean注册**自动配置类中的`@Bean`方法通过反射被解析和调用:```java//自动配置类示例@Configuration@ConditionalOnClass(RedisConnectionFactory.class)publicclassRedisAutoConfiguration{@Bean@ConditionalOnMissingBeanpublicRedisTemplate<String,Object>redisTemplate(){returnnewRedisTemplate<>();}}//Spring内部处理伪代码Method[]methods=configClass.getDeclaredMethods();for(Methodmethod:methods){if(method.isAnnotationPresent(Bean.class)){//反射调用@Bean方法获取Bean实例ObjectbeanInstance=method.invoke(configClassInstance);beanFactory.registerBean(beanName,beanInstance);}}```###4.**配置属性的动态绑定**`@ConfigurationProperties`利用反射将配置文件属性注入Bean字段:```yaml#application.ymlspring.datasource:url:jdbc:mysql://localhost/testusername:root``````java@ConfigurationProperties(prefix="spring.datasource")publicclassDataSourceProperties{privateStringurl;//反射注入值privateStringusername;//setter方法被反射调用publicvoidsetUrl(Stringurl){this.url=url;}}```###反射在自动配置中的关键作用总结|**阶段**|**反射操作**|**目的**||------------------------|---------------------------------------|-----------------------------||加载配置类|`Class.forName()`加载类|获取自动配置类元数据||条件注解校验|`ClassLoader.loadClass()`检查类存在性|决定是否启用配置||Bean方法执行|`Method.invoke()`调用@Bean方法|创建Bean实例||属性绑定|`Field.set()`/调用setter方法|注入外部化配置|>**性能优化**:SpringBoot启动时通过**ASM字节码扫描**(非反射)预读类元数据,减少反射调用次数[^1][^2]。实际反射操作仅在需要实例化或动态检查时触发。###自动配置流程中的反射时序1.**启动阶段**-扫描`spring.factories`→反射加载配置类名2.**条件过滤阶段**-反射检查`@Conditional*`注解条件→过滤无效配置类3.**Bean注册阶段**-反射调用配置类的`@Bean`方法→注册Bean到容器4.**属性绑定阶段**-反射注入`application.properties`的值到`@ConfigurationProperties`类§§相关问题§§1.`@ConditionalOnClass`和`@ConditionalOnMissingBean`在反射处理机制上有何不同?2.SpringBoot如何避免自动配置过程中的重复反射操作?3.如何自定义一个基于反射的条件注解?4.自动配置类中的`@Bean`方法为何必须是非final的?</think>### Spring Boot自动配置中反射机制的核心原理 Spring Boot自动配置的核心是**基于条件注解的动态加载机制**,反射在此过程中扮演关键角色。以下是反射在自动配置中的具体应用原理: --- #### 1. **自动配置类的加载与过滤(反射扫描)** Spring Boot启动时通过反射扫描`META-INF/spring.factories`文件中的配置类: ```java // SpringFactoriesLoader 核心逻辑 List<String> factoryNames = loadFactoryNames(EnableAutoConfiguration.class, classLoader); for (String factoryName : factoryNames) { Class<?> configClass = Class.forName(factoryName); // 反射加载类[^3][^4] if (shouldSkip(configClass)) continue; // 反射检查条件注解 autoConfigurationClasses.add(configClass); } ``` - **反射操作**:`Class.forName()`动态加载配置类 - **目的**:获取所有候选自动配置类(如`RedisAutoConfiguration`、`DataSourceAutoConfiguration`) --- #### 2. **条件注解的动态评估(反射校验)** 核心条件注解(如`@ConditionalOnClass`)通过反射验证运行环境: ```java // OnClassCondition 处理器伪代码 public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { // 反射获取注解中要求的类名 String[] requiredClasses = metadata.getAnnotationAttributes( ConditionalOnClass.class.getName()).get("value"); // 反射检查类路径是否存在 for (String className : requiredClasses) { if (!ClassUtils.isPresent(className, classLoader)) { // 反射检查 return false; // 条件不满足 } } return true; } ``` - **关键反射方法**: - `ClassLoader.loadClass()`:检查类是否存在 - `Class.getAnnotation()`:获取条件注解元数据 - **典型注解**: - `@ConditionalOnClass`:反射验证类路径是否存在 - `@ConditionalOnMissingBean`:反射检查容器中是否缺少Bean[^4] --- #### 3. **配置类的方法解析与Bean注册反射调用)** 满足条件的配置类通过反射实例化并处理`@Bean`方法: ```java // ConfigurationClassParser 核心逻辑 for (Method method : configClass.getDeclaredMethods()) { if (method.isAnnotationPresent(Bean.class)) { // 反射创建Bean实例 Object beanInstance = method.invoke(configClassInstance); beanFactory.registerSingleton(beanName, beanInstance); } } ``` - **反射操作**: - `Method.invoke()`:动态调用`@Bean`方法 - `Constructor.newInstance()`:实例化配置类 - **动态代理支持**:对`@Configuration`类生成CGLIB代理(增强Bean作用域管理) --- #### 4. **配置属性的动态绑定(反射注入)** `@ConfigurationProperties`通过反射将属性注入Bean: ```properties # application.properties spring.datasource.url=jdbc:mysql://localhost/db spring.datasource.username=root ``` ```java // 绑定属性到Bean的伪代码 Field[] fields = target.getClass().getDeclaredFields(); for (Field field : fields) { String propertyKey = "spring.datasource." + field.getName(); if (env.containsProperty(propertyKey)) { field.setAccessible(true); field.set(target, env.getProperty(propertyKey)); // 反射注入值 } } ``` --- ### 自动配置流程中的反射时序 ```mermaid sequenceDiagram participant S as SpringApplication.run() participant L as SpringFactoriesLoader participant C as ConditionEvaluator participant B as BeanFactory S->>L: 反射加载spring.factories L->>C: 返回候选配置类列表 loop 遍历每个配置类 C->>C: 反射检查@ConditionalOnClass等条件 alt 条件满足 C->>B: 注册配置类 B->>B: 反射调用@Bean方法 B->>B: 反射注入@ConfigurationProperties else 条件不满足 C->>C: 跳过配置类 end end ``` --- ### 反射优化的关键技术 1. **元数据缓存**: Spring Boot启动后缓存反射获取的`Method`/`Field`对象,避免重复反射调用[^1] 2. **ASM字节码扫描**: 在条件检查阶段使用ASM直接读取字节码(非反射),减少类加载开销[^2] 3. **条件注解预过滤**: `AutoConfigurationImportSelector`优先过滤明显不满足条件的配置类,减少反射操作[^4] > **性能提示**:Spring Boot 3.x 进一步优化反射性能,通过GraalVM原生映像支持提前编译反射元数据[^1] --- ### 典型自动配置示例:DataSource 1. `DataSourceAutoConfiguration`被加载 2. 反射检查`@ConditionalOnClass(DataSource.class)` → 验证JDBC驱动是否存在 3. 反射注入`@ConfigurationProperties(prefix="spring.datasource")`的属性 4. 反射调用`@Bean`方法创建`DataSource`实例
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值