关于bean的加载方式,spring提供了各种各样的形式。因为spring管理bean整体上来说就是由spring维护对象的生命周期,所以bean的加载可以从大的方面划分成2种形式。已知类并交给spring管理,和已知类名并交给spring管理。有什么区别?一个给.class,一个给类名字符串。内部其实都一样,都是通过spring的BeanDefinition对象初始化spring的bean

方式一:配置文件+标签

<?xml version=”1.0” encoding=”UTF-8”?>
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">


  1. <!--xml方式声明第三方开发的bean--><br /> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"/><br /> <bean class="com.alibaba.druid.pool.DruidDataSource"/><br /> <bean class="com.alibaba.druid.pool.DruidDataSource"/><br /></beans>

方式二:配置文件扫描+注解定义bean

这里可以使用的注解有@Component以及三个衍生注解@Service、@Controller、@Repository。
@Component(“tom”)
public class Cat {
}
@Service
public class Mouse {
}
@Component
public class DbConfig {
@Bean
public DruidDataSource dataSource(){
DruidDataSource ds = new DruidDataSource();
return ds;
}
}

<?xml version=”1.0” encoding=”UTF-8”?>
xmlns:context=”http://www.springframework.org/schema/context
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
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
“>



方式二声明bean的方式是目前企业中较为常见的bean的声明方式,但是也有缺点。方式一中,通过一个配置文件,你可以查阅当前spring环境中定义了多少个或者说多少种bean,但是方式二没有任何一个地方可以查阅整体信息,只有当程序运行起来才能感知到加载了多少个bean。

方式三:注解方式声明配置类

@ComponentScan({“com.itheima.bean”,”com.itheima.config”})
public class SpringConfig3 {
@Bean
public DogFactoryBean dog(){
return new DogFactoryBean();
}
}

使用FactroyBean接口
  1. 补充一个小知识,spring提供了一个接口FactoryBean,也可以用于声明bean,只不过实现了FactoryBean接口的类造出来的对象不是当前类的对象,而是FactoryBean接口泛型指定类型的对象。如下列,造出来的bean并不是DogFactoryBean,而是Dog。有什么用呢?可以在对象初始化前做一些事情,下例中的注释位置就是让你自己去扩展要做的其他事情的。<br />public class DogFactoryBean implements FactoryBean<Dog> {<br /> @Override<br /> public Dog getObject() throws Exception {<br /> Dog d = new Dog();<br /> //.........<br /> return d;<br /> }<br /> @Override<br /> public Class<?> getObjectType() {<br /> return Dog.class;<br /> }<br /> @Override<br /> public boolean isSingleton() {<br /> return true;<br /> }<br />}<br /> 通常实现了FactoryBean接口的类使用@Bean的形式进行加载,当然你也可以使用@Component去声明DogFactoryBean,只要被扫描加载到即可,但是这种格式加载总觉得怪怪的,指向性不是很明确。<br />@ComponentScan({"com.itheima.bean","com.itheima.config"})<br />public class SpringConfig3 {<br /> @Bean<br /> public DogFactoryBean dog(){<br /> return new DogFactoryBean();<br /> }<br />}

注解格式导入XML格式配置的bean

@Configuration
@ImportResource(“applicationContext1.xml”)
public class SpringConfig32 {
}

proxyBeanMethods属性

@Configuration(proxyBeanMethods = true)
public class SpringConfig33 {
@Bean
public Cat cat(){
return new Cat();
}
}
public class App33 {
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig33.class);
String[] names = ctx.getBeanDefinitionNames();
for (String name : names) {
System.out.println(name);
}
System.out.println(“————————————-“);
SpringConfig33 springConfig33 = ctx.getBean(“springConfig33”, SpringConfig33.class);
System.out.println(springConfig33.cat());
System.out.println(springConfig33.cat());
System.out.println(springConfig33.cat());
}
}

方式四:使用@Import注解注入bean

@Import({Dog.class,DbConfig.class})
public class SpringConfig4 {
}

使用@Import注解注入配置类
除了加载bean,还可以使用@Import注解加载配置类<br />@Import(DogFactoryBean.class)<br />public class SpringConfig4 {<br />}

方式五:编程形式注册bean

    前面介绍的加载bean的方式都是在容器启动阶段完成bean的加载,下面这种方式就比较特殊了,可以在容器初始化完成后手动加载bean。通过这种方式可以实现编程式控制bean的加载。<br />public class App5 {<br />    public static void main(String[] args) {<br />        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);<br />        //上下文容器对象已经初始化完毕后,手工加载bean<br />        ctx.register(Mouse.class);<br />    }<br />}

方式六:导入实现了ImportSelector接口的类

public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata metadata) {
//各种条件的判定,判定完毕后,决定是否装载指定的bean
boolean flag = metadata.hasAnnotation(“org.springframework.context.annotation.Configuration”);
if(flag){
return new String[]{“com.itheima.bean.Dog”};
}
return new String[]{“com.itheima.bean.Cat”};
}
}

方式七:导入实现了ImportBeanDefinitionRegistrar接口的类

public class MyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {
BeanDefinition beanDefinition =
BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl2.class).getBeanDefinition();
registry.registerBeanDefinition(“bookService”,beanDefinition);
}
}

方式八:导入实现了BeanDefinitionRegistryPostProcessor接口的类

public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
BeanDefinition beanDefinition =
BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl4.class).getBeanDefinition();
registry.registerBeanDefinition(“bookService”,beanDefinition);
}
}

总结

  1. bean的定义由前期xml配置逐步演化成注解配置,本质是一样的,都是通过反射机制加载类名后创建对象,对象就是spring管控的bean
  2. @Import注解可以指定加载某一个类作为spring管控的bean,如果被加载的类中还具有@Bean相关的定义,会被一同加载
  3. spring开放出了若干种可编程控制的bean的初始化方式,通过分支语句由固定的加载bean转成了可以选择bean是否加载或者选择加载哪一种bean