SpringBoot bean的多种加载方式示例详解
作者:冬天vs不冷
一、xml配置文件
配置文件spring-bean.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"> <!--xml方式声明自己开发的bean--> <bean id="person" class="com.xc.entity.Person"/> <bean class="com.xc.entity.Person"/> <bean class="com.xc.entity.Person"/> <!--xml方式声明第三方开发的bean--> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"/> </beans>
加载xml
public class App { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring-bean.xml"); for (String beanDefinitionName : context.getBeanDefinitionNames()) { System.out.println(beanDefinitionName); } } }
输出结果:
person
com.xc.entity.Person#0
com.xc.entity.Person#1
dataSource
二、注解定义bean
1、使用AnnotationConfigApplicationContext对象加载
public class App { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); for (String beanDefinitionName : context.getBeanDefinitionNames()) { System.err.println(beanDefinitionName); } } }
public class MyConfig { }
使用AnnotationConfigApplicationContext
对象加载MyConfig,即使MyConfig类什么注解没有,也会被注册为bean。
2、加载本地类 使用的注解@Component
或其他衍生注解@Service
、@Controller
、@Repository
@Service public class BookServiceImpl implements BookService { }
3、加载第三方jar类
由于我们无法在第三方提供的技术源代码中去添加上述4个注解,因此当你需要加载第三方开发的bean
的时候可以使用@Component
和@Configuration
都可以,一般引入第三方倾向于后者。
//@Component @Configuration public class DbConfig { @Bean public DruidDataSource dataSource(){ return new DruidDataSource(); } @Bean public Cat cat(){ Cat cat = new Cat(); cat.setDruidDataSource(dataSource()); return cat; } }
@Configuration(proxyBeanMethods = true)
:默认设置,使用了cglib动态代理
,cat里的dataSource和@Bean创建的dataSource是同一个对象
,可以理解为单例
@Configuration(proxyBeanMethods = false)
:此时和@Component注解功能一样,cat里的dataSource和@Bean创建的dataSource不是同一个对象
,可以理解为多例
- 如果配置中@Bean标识的方法之间
不存在依赖调用
的话,可以设置为false,可以避免拦截方法进行代理操作,提升性能
三、特殊方式
3.1、使用FactroyBean接口
- spring提供了一个接口
FactoryBean
,也可以用于声明bean
- 实现了FactoryBean接口的类造出来的对象不是当前类的对象,而是FactoryBean接口
泛型
指定类型的对象 - 一般用来创建复杂对象
public class DogFactoryBean implements FactoryBean<Dog> { //创建bean的复杂过程 @Override public Dog getObject() throws Exception { Dog d = new Dog(); //......... return d; } //bean的类型 @Override public Class<?> getObjectType() { return Dog.class; } //bean是否单例 @Override public boolean isSingleton() { return true; } }
配置类
public class MyConfig { @Bean public DogFactoryBean dog(){ return new DogFactoryBean(); } }
启动类
public class App { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); System.out.println(context.getBean("dog")); } }
3.2、注解导入XML格式配置的bean
- 场景:旧项目xml配置bean融入配置类项目中
@ImportResource
在配置类上直接写上要被融合的xml配置文件名即可
@Configuration @ImportResource(locations = "spring-bean.xml") public class SpringConfig { }
3.3、通过上下文ApplicationContext注册bean
在容器初始化完成后手动加载bean,创建方式很多
方式一:无参构造
public class App { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); //上下文容器对象已经初始化完毕后,手工加载bean ctx.register(Mouse.class); } }
方式二:多参构造
public class App { public static void main(String[] args) { AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class); //上下文容器对象已经初始化完毕后,手工加载bean ctx.registerBean("tom", Cat.class,"花猫",3); } }
四、@Import注解注入bean
1、@Import导入普通类
- 场景:将一个无任何注解的类加载为bean
- 一个类@Improt只能用一次,想要导入多个使用{…,…}
- 只有MyConfig加载为bean,@Import才生效
@Configuration //@Import(Pig.class) @Import({Dog.class,Cat.class}) public class MyConfig { }
public class App { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); for (String beanDefinitionName : context.getBeanDefinitionNames()) { System.err.println(beanDefinitionName); } } }
输出结果:
myConfig
com.xc.springboot.bean.Dog
com.xc.springboot.bean.Cat
2、@Import导入实现了ImportSelector接口的类
- 可以通过添加
判断语句
就可以实现对bean的加载控制
- 返回值为多个
全路径类名字符串
- metadata为@Import注解类的元数据,可以拿到MyConfig类上所有的注解,注解里的属性,继承的接口,父类等等信息
- 如下则是判断MyCofig类上有@Configuration注解则加载Dog类,否则加载Cat类
public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata metadata) { System.out.println("元数据Class名称:" + metadata.getClassName()); //各种条件的判定,判定完毕后,决定是否装载指定的bean boolean flag = metadata.hasAnnotation("org.springframework.context.annotation.Configuration"); if(flag){ return new String[]{"com.xc.springboot.bean.Dog"}; } return new String[]{"com.xc.springboot.bean.Cat"}; } }
配置类
@Configuration @Import(MyImportSelector.class) public class MyConfig { }
启动类
public class App { public static void main(String[] args) { AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class); for (String beanDefinitionName : context.getBeanDefinitionNames()) { System.err.println(beanDefinitionName); } } }
输出结果:
元数据Class名称:com.xc.springboot.bean.MyConfig
myConfig
com.xc.springboot.bean.Dog
3、@Import导入实现了ImportBeanDefinitionRegistrar接口的类
- 返回值为void,通过
Bean定义(beanDefinition)
注册创建新的bean - 同样可以通过添加判断语句就可以实现bean的加载控制,更加细粒度判断bean
public class MyRegistrar implements ImportBeanDefinitionRegistrar { @Override public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) { BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookService.class).getBeanDefinition(); registry.registerBeanDefinition("bookService",beanDefinition); } }
4、@Import导入实现了BeanDefinitionRegistryPostProcessor接口的类
- BeanDefinitionRegistryPostProcessor接口,其中有两个重要的方法:
postProcessBeanDefinitionRegistry
:用于注册新的BeanDefinitionpostProcessBeanFactory
:用于在BeanFactory准备好后
进行自定义操作
- BeanDefinitionRegistryPostProcessor:bean定义注册
最后
的处理器(在以上处理后执行此操作),如果想bean最后确定一个值,可以在这里操作
public class MyBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException { // 通过 BeanDefinitionBuilder 创建一个新的 Bean 定义 BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(MyCustomBean.class); // 注册这个 bean 定义到 registry 中 registry.registerBeanDefinition("myCustomBean", builder.getBeanDefinition()); System.out.println("Bean definition registered: myCustomBean"); } @Override public void postProcessBeanFactory(org.springframework.beans.factory.config.ConfigurableListableBeanFactory beanFactory) throws BeansException { // 在这里可以对 BeanFactory 进行进一步的配置 System.out.println("Bean factory post-processing"); } }
注意:所有通过@Import导入的bean名称为全路径名
到此这篇关于SpringBoot基础(四):bean的多种加载方式的文章就介绍到这了,更多相关SpringBoot bean加载方式内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!