我们希望Spring框架帮忙管理Bean实例,以便得到框架所带来的种种功能,例如依赖注入等。将一个类纳入Spring容器管理的方式有几种,它们可以解决在不同场景下创建实例的需求。
-
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 https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean name="testService" class="com.example.demo.test.TestService"/> </beans>
- 需要指定配置文件来初始化Spring容器
ApplicationContext context = new ClassPathXmlApplicationContext("services.xml");
- 这种方式已经过时了,在历史项目中可能还有身影。
- 在配置文件中还可对实例化过程进行一些调整,例如可延迟到实例使用时才真正初始化(延时加载)、实例作用域等。
- 需要指定配置文件来初始化Spring容器
-
在目标类头上加注解
import org.springframework.stereotype.Service; @Service public class TestService { }
- 目前大家普遍使用Spring boot,可以很方便地在目标类上加注解,框架使用
AnnotationConfigApplicationContext
扫描类识别到注解后,将类进行初始化。默认只会扫描启动类的包目录,你可以通过@ComponentScan来配置其它包路径。 - 那么使用哪些类才会被扫描到呢?
- 只要该注解类中有增加
org.springframework.stereotype.Component
元注解,像上面的@Service注解类头上就有。 - 常见的有@ControllerAdvice、@Configuration、@Controller、@Repository、@Service、@Autowired、@Resource和@Component等。
- 只要该注解类中有增加
- 目前大家普遍使用Spring boot,可以很方便地在目标类上加注解,框架使用
-
通过编程方式
@Configuration public class TestConfiguration { @Bean public TestService getTestService() { return new TestService(); } }
- 这种方式可以让开发者更容易的控制Bean实例化过程,例如可以从外部来源获取参数,最终将类实例化。
-
获取ApplicationContext来构建
public static void main(String[] args) { ConfigurableApplicationContext context = SpringApplication.run(AppStater.class, args); BeanDefinitionBuilder bdf = BeanDefinitionBuilder.genericBeanDefinition(TestService.class); ((DefaultListableBeanFactory) context.getAutowireCapableBeanFactory()) .registerBeanDefinition("testService", bdf.getBeanDefinition()); }
- 这种方式需要注意使用Bean的时机,因为在Spring容器初始时并没有创建它,所以这种方式也可以实现动态加载Bean。
- 在实现类似插件这种机制时,必不可少的就是动态加载,在程序启动时并不知道将会实例化什么类,等到运行过程中通过配置或其它外部源动态获取要实例化的类。
-
为了获取Spring容器,一般会创建一个工具类,方便开发者在代码任意位置就能拿到容器,下面代码可以拿走即用。
package cn.com.example.app.commons.spring; import org.springframework.beans.BeansException; import org.springframework.beans.factory.DisposableBean; import org.springframework.context.ApplicationContext; import org.springframework.context.ApplicationContextAware; import org.springframework.context.annotation.Lazy; import org.springframework.stereotype.Component; import org.springframework.util.Assert; /** * 以静态变量保存 Spring ApplicationContext,可在任何代码任何地方任何时候取出ApplicationContext。 * * @author tianmingxing <mx.tian@qq.com> * @date 2022-03-08 */ @Component @Lazy(value = false) public class SpringContextHolder implements ApplicationContextAware, DisposableBean { public static ApplicationContext ctx = null; @SuppressWarnings("unchecked") public static <T> T getBean(String name) { assertContextInjected(); return (T) ctx.getBean(name); } public static <T> T getBean(Class<T> clazz) { assertContextInjected(); return ctx.getBean(clazz); } public static ApplicationContext getContext() { assertContextInjected(); return ctx; } @Override public void destroy() throws Exception { ctx = null; } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { ctx = applicationContext; } }
-
除此之外还有一些方法,采用框架的一些特性,在过程中顺便完成实例初始化,算是被动的做了这件事情。