通过注解模式 装载Bean 和 Spring Boot一些注解

本文介绍如何在Spring框架中整合MyBatis,并详细解释了必要的配置步骤及常用的注解,包括如何通过@Autowired和@Qualifier实现依赖注入。

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

Mybatis 在配置Mybatis 的datasource 和sessionFactory

org.springframework.jdbc.datasource.DriverManagerDataSource

org.mybatis.spring.SqlSessionFactoryBean

之后要使用接口调用xml里的sql语句 还需申明 Mybatis的Mapper扫描包以及 sessionfactory

<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
		<!-- 扫描本包下面的MapperDao(接口)托管给Spring IOC -->
		<property name="basePackage" value="com.zx.Dao"></property>
		<property name="sqlSessionFactoryBeanName" value="sessionFactory"></property>
	</bean>

这样 就可以直接通过@Autowired 将对应的Mapper接口租入使用

附上几个注解的解释 和用法

@Repository注解:用于标注数据访问组件,即DAO组件
@Service注解:用于标注业务层组件
@Controller注解:用于标注控制层组件(如struts中的action)
@Component注解:泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。

@Controller

@Controller("Bean的名称")

定义控制层Bean,如Action

 

@Service          

@Service("Bean的名称")

定义业务层Bean

 

@Repository   

@Repository("Bean的名称")

定义DAO层Bean

 

@Component  

定义Bean, 不好归类时使用.

 

--自动装配Bean (选用一种注解就可以)

@Autowired  (Srping提供的)

默认按类型匹配,自动装配(Srping提供的),可以写在成员属性上,或写在setter方法上

 

@Autowired(required=true)  

一定要找到匹配的Bean,否则抛异常。 默认值就是true 

 

@Autowired

@Qualifier("bean的名字") 

按名称装配Bean,与@Autowired组合使用,解决按类型匹配找到多个Bean问题。

 

@Resource   JSR-250提供的

默认按名称装配,当找不到名称匹配的bean再按类型装配.

可以写在成员属性上,或写在setter方法上

可以通过@Resource(name="beanName") 指定被注入的bean的名称, 要是未指定name属性, 默认使用成员属性的变量名,一般不用写name属性.

@Resource(name="beanName")指定了name属性,按名称注入但没找到bean, 就不会再按类型装配了.

 

@Inject   是JSR-330提供的

按类型装配,功能比@Autowired少,没有使用的必要。

 

--定义Bean的作用域和生命过程

@Scope("prototype")

值有:singleton,prototype,session,request,session,globalSession

 

@PostConstruct 

相当于init-method,使用在方法上,当Bean初始化时执行。

 

@PreDestroy 

相当于destory-method,使用在方法上,当Bean销毁时执行。

 

--声明式事务

@Transactional  

 

关于Spring Boot 通过注解注册托管Bean的时候 他默认扫描的是入口类Application.class的同包下的类

如果Application类所在的包为:io.github.gefangshuai.app,则只会扫描io.github.gefangshuai.app包及其所有子包,如果service或dao所在包不在io.github.gefangshuai.app及其子包下,则不会被扫描!

也就是不会注册成为Bean通过自动注入注解注入的时候就会出错

这个时候 我们需要用

@ComponentScan(basePackages={"com.zx"})

手动设置扫描的包 然后就会找到该包下面所有申明为Bean的类 进入IOC托管

转载于:https://my.oschina.net/u/2970507/blog/1794114

<think>我们正在处理的问题是:Javaagent代理包启动后导致原应用中的@ConditionalOnClass注解Bean未成功加载。 根据之前的讨论,我们知道这是因为Javaagent在类加载过程中进行了字节码增强,可能干扰了Spring Boot在启动时对类路径的检查。 解决方案的核心思路: 1. 确保在Spring Boot检查条件注解之前,目标类已经被加载。 2. 避免Javaagent对条件注解相关类的字节码进行修改,或者延迟条件检查。 参考之前的解决方案,我们可以采取以下步骤: 方案一:在Javaagent的premain方法中预加载关键类 - 在Javaagent启动时,通过Class.forName()主动加载目标类,这样在Spring Boot启动时,这些类已经被加载,条件注解就能检测到。 方案二:在Javaagent的ClassTransformer中跳过对条件注解相关类的处理 - 避免对Spring的条件注解类(如OnClassCondition)以及目标类进行字节码增强,防止影响其加载判断。 方案三:调整条件检查的时机,使用自定义Condition实现 - 将条件检查延迟到Spring上下文初始化阶段,而不是在Bean定义注册阶段。 方案四:隔离Javaagent的类加载器,防止污染应用类加载器。 现在,我们结合用户提供的引用内容,特别是引用[1]引用[2]中关于@ConditionalOnClass的说明,来具体实现这些方案。 具体步骤: 1. 预加载关键类(方案一): 在Javaagent的premain方法中,列出所有可能被@ConditionalOnClass注解所依赖的类,并尝试加载它们。 注意:由于这些类可能不存在,所以需要捕获ClassNotFoundException。 示例代码: ```java public static void premain(String args, Instrumentation inst) { // 预加载ConditionalOnClass可能依赖的类 String[] classesToPreload = { "com.example.RequiredClass1", "com.example.RequiredClass2" }; for (String className : classesToPreload) { try { Class.forName(className); } catch (ClassNotFoundException e) { // 忽略,如果类不存在,则后续条件注解自然会失效 } } // 添加ClassTransformer inst.addTransformer(new MyClassTransformer()); } ``` 2. 在ClassTransformer中跳过特定类(方案二): 在transform方法中,判断当前正在加载的类是否属于条件注解相关类或目标类,如果是则跳过。 示例代码: ```java public class MyClassTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, String className, Class<?> classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) { // 将类名从内部形式(如'java/lang/Object')转换为外部形式(如'java.lang.Object') String dotClassName = className.replace('/', '.'); // 跳过条件注解相关的类目标类 if (dotClassName.startsWith("org.springframework.boot.autoconfigure.condition") || dotClassName.equals("com.example.RequiredClass1") || dotClassName.equals("com.example.RequiredClass2")) { return null; // 返回null表示不进行字节码增强 } // 否则进行正常的字节码处理 // ... } } ``` 3. 自定义条件检查(方案三): 在Spring应用中,将@ConditionalOnClass替换为自定义的条件检查,这样可以在Spring上下文初始化时再检查类是否存在。 示例代码: ```java @Configuration public class MyConfiguration { @Bean @Conditional(MyOnClassCondition.class) public MyBean myBean() { return new MyBean(); } } public class MyOnClassCondition implements Condition { @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) { try { // 在Spring上下文初始化时再加载类 context.getClassLoader().loadClass("com.example.RequiredClass1"); return true; } catch (ClassNotFoundException e) { return false; } } } ``` 4. 类加载器隔离(方案四): 在Javaagent的MANIFEST.MF中指定Boot-Class-PathLauncher-Agent-Class,使得Javaagent使用独立的类加载器。 在MANIFEST.MF中添加: ``` Boot-Class-Path: agent-libs/ Launcher-Agent-Class: com.example.AgentBootstrapper ``` 这样,Javaagent的类将由系统类加载器加载,而不会影响应用的类加载器。 验证方案: 在Spring Boot的application.properties中开启条件注解的调试日志: logging.level.org.springframework.boot.autoconfigure=DEBUG 启动应用,观察日志中关于条件注解的输出,确认目标类是否被正确检测到。 预防措施: - 在开发Javaagent时,避免在transform方法中抛出异常,以免中断类加载过程。 - 尽量缩小字节码增强的范围,只对必要的类进行增强。 根据引用[4]的内容,Spring Boot的自动装配机制依赖于条件注解spring.factories文件。因此,确保条件注解的正确执行是自动装配成功的关键。 最后,我们生成相关问题: 1. 如何诊断Javaagent与Spring Boot的类加载冲突? 2. `@ConditionalOnClass``@ConditionalOnMissingClass`的工作原理有何区别? 3. 在Javaagent中如何安全地修改Spring核心类的字节码? 4. Spring Boot的自动配置条件判断机制在启动流程的哪个阶段执行? 5. 如何编写不干扰Spring上下文初始化的Javaagent? 注意:在回答中引用的内容末尾添加引用标识,如[^1]。</think>针对 Javaagent 代理包导致 `@ConditionalOnClass` 注解 Bean 未加载的问题,以下是系统化的解决方案及原理分析: ### 一、问题根源分析 1. **类加载时序冲突** Javaagent 通过 `ClassFileTransformer` 修改字节码时,可能**延迟或干扰**目标类的加载过程[^4]。 Spring Boot 的 `@ConditionalOnClass` 在**Bean定义注册阶段**(`BeanDefinitionRegistryPostProcessor`)执行类存在性检查[^1],若此时目标类尚未被 Javaagent 加载完成,条件判断将失败。 2. **类加载器隔离失效** Javaagent 默认使用**系统类加载器**(`sun.misc.Launcher$AppClassLoader`),而 Spring Boot 应用使用 `LaunchedURLClassLoader`。当 Javaagent 修改字节码时,可能破坏双亲委派机制,导致类加载路径不一致[^2]。 --- ### 二、解决方案(四步递进) #### 方案1:预加载关键类(推荐) 在 Javaagent 的 `premain` 方法中强制加载目标类: ```java public static void premain(String args, Instrumentation inst) { // 预加载ConditionalOnClass依赖的类 try { Class.forName("com.example.RequiredClass"); // 显式触发类加载 } catch (ClassNotFoundException ignored) {} inst.addTransformer(new SafeTransformer()); } ``` **原理**:在 Spring 启动前强制 JVM 加载目标类,确保条件检查时类已存在[^1]。 #### 方案2:定制安全的 ClassTransformer 跳过条件注解相关类的字节码修改: ```java public class SafeTransformer implements ClassFileTransformer { @Override public byte[] transform(ClassLoader loader, String className, ...) { // 跳过Spring条件注解相关类 if (className.startsWith("org/springframework/boot/autoconfigure/condition") || className.equals("com/example/RequiredClass")) { return null; // 不修改字节码 } // 其他字节码增强逻辑... } } ``` **原理**:避免对条件判断机制的关键类进行字节码增强,防止加载时序被破坏[^2]。 #### 方案3:延迟条件检查 用自定义 `Condition` 替代 `@ConditionalOnClass`: ```java @Configuration @Conditional(CustomCondition.class) // 自定义条件检查 public class MyConfig { // Bean定义 } public class CustomCondition implements Condition { @Override public boolean matches(ConditionContext ctx, AnnotatedTypeMetadata meta) { try { // 延迟到上下文初始化阶段检查 ctx.getClassLoader().loadClass("com.example.RequiredClass"); return true; } catch (ClassNotFoundException e) { return false; } } } ``` **优势**:将类存在性检查推迟到 Spring 上下文初始化阶段,避开 Javaagent 的加载干扰[^1][^4]。 #### 方案4:类加载器隔离 在 Javaagent 的 `MANIFEST.MF` 中声明独立类加载器: ```manifest Boot-Class-Path: agent-libs/ Launcher-Agent-Class: com.example.AgentBootstrapper Can-Redefine-Classes: false Can-Retransform-Classes: false ``` **作用**:隔离 Javaagent 的类加载行为,防止污染应用类加载器[^4]。 --- ### 三、验证与调试 1. **开启条件注解调试日志** 在 `application.properties` 中添加: ```properties logging.level.org.springframework.boot.autoconfigure=DEBUG ``` 观察日志输出: ``` DEBUG o.s.b.a.condition.OnClassCondition - @ConditionalOnClass found required class 'com.example.RequiredClass' ``` 2. **诊断类加载状态** 在 Javaagent 中添加诊断代码: ```java public byte[] transform(...) { System.out.println("Loading: " + className); // 打印加载类 // ... } ``` --- ### 四、预防措施 1. **Javaagent 开发规范** - 设置 `canRetransform=false` 减少类重加载次数 - 避免在 `ClassFileTransformer` 中抛出异常中断加载 2. **Spring Boot 适配优化** ```java @Bean @ConditionalOnClass(name = "com.example.RequiredClass", value = ClassLoader.class) // 显式指定类加载器 public MyBean myBean() { return new MyBean(); } ``` > **根本解决原理**:通过预加载、字节码处理隔离或延迟检查机制,使 Javaagent 的类修改时序与 Spring 的条件判断阶段重新对齐[^1][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值