ClassPathXmlApplicationContext
获取容器,这个方法需要配置 applicationConfig.xml
来配合初始化容器中的 Bean
ApplicationContext context = newClassPathXmlApplicationContext("applicationContext.xml"); context.refresh();复制代码
<!-- applicationConfig.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"> <!-- 创建项目根目录下的src/main/resources目录,这是maven项目约定的资源文件目录。 --> <!-- 创建resources目录后,记得reimport Maven Project,否则idea识别不了。 --> <!-- 在resources目录下,使用idea创建spring context的xml配置文件。 --> <bean id="customerBean" class="cn.edu.dgut.sai.Customer"> <property name="name" value="hello"/> </bean> </beans>复制代码
AnnotationConfigApplicationContext
获取容器,这个方法需要配置一个 配置类 来配合初始化容器中的 Bean
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); context.refresh();复制代码
/** * Configuration:此类为配置类 * ComponentScan:告知容器扫描此类所在包所有的类以及子包下所有的类的注解 */ @Configuration @ComponentScan public class Config { }复制代码
使用 Component
在类上面注解,容器进行扫描时,容器自动将此类注册为 Bean
@Component public class Player { private String name; private String age; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getAge() { return age; } public void setAge(String age) { this.age = age; } }复制代码
此外,还可以用 @Service
、 @Controller
等注解配置Bean,区别在于 Component
是通用注解,而 Service
则是适用与Service业务层, Controller
适用于Web视图层
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class); context.registerBean("UserBean",User.class); context.refresh();复制代码
使用 Junit
进行测试,不再需要机械重复地创建一个类,然后加入 main
方法,然后在 main
方法获取容器实例 ApplicationContext
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(loader = AnnotationConfigContextLoader.class, classes = Config.class) public class SpringTest { @Test public void testUser() { } }复制代码
classes需要填写配置类的字节码文件
当一个类成为 Bean
,继承 InitializingBean
接口并且实现接口的 afterPropertiesSet
方法的时候,当该 Bean
被容器注册并且实例化后的时候, afterPropertiesSet
方法就会被调用(回调)。
同样的,当一个类成为 Bean
,继承了 DisposableBean
接口并且实现接口的destroy方法的时候,当该 Bean
被销毁之前, destroy
方法就会自动被调用(回调)
public class User implements InitializingBean, DisposableBean { private String name; private String sex; public User() { } @Override public void afterPropertiesSet() throws Exception { System.out.println("afterPropertiesSet回调"); } @Override public void destroy() throws Exception { System.out.println("User: destroy"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } } 复制代码
这个接口的作用是令Bean能够获取容器的实例,进而通过编程的方法进行操作,例如下面,User Bean希望获取其他Customer Bean,就创建一个成员变量,通过这个接口获取容器实例,用成员变量保存容器实例,进而获取Customer Bean。
public class User implements InitializingBean, DisposableBean, ApplicationContextAware { private String name; private String sex; private ApplicationContext context; public User() { System.out.println("初始化"); } @Override public void destroy() throws Exception { System.out.println("User: destroy"); } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } @Override public void afterPropertiesSet() throws Exception { System.out.println("afterPropertiesSet回调"); } @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { System.out.println("applicationContext注入"); this.context = applicationContext; Customer customerBean = (Customer)this.context.getBean("customerBean"); System.out.println(customerBean); } }复制代码
此注解主要作用是懒加载,一个Bean被ApplicationContext注册的时候, 不会立即实例化 ,需要等到调用的时候,才会被实例化
定义Bean的范围,一般是选值为 singleton
或 prototype
, singleton
表示为单例, prototype
表示为多例
回调函数,当一个类注册为 Bean
,并且继承 BeanPostProcessor
接口,实现其接口的 postProcessBeforeInitialization
和 postProcessAfterInitialization
方法的时候,在这个容器中,只要有 Bean
注册实例化,就会 自动调用
此接口的两个方法。 有多少个Bean注册实例化,就调用多少次
。 postProcessBeforeInitialization
会在 Bean
注册实例化之前
自动被调用, postProcessAfterInitialization
会在 Bean
注册实例化
被自动调用。可以从这两个方法之中的参数, 获取
Bean的 实例
和注册为Bean的 命名
注意:当使用context.register方法动态注册Bean的时候,Bean并不会实例化,不会触发InitializingBean、ApplicationContextAware等回调函数。当使用getBean的方法的时候,即初始化、实例化Bean,就会触发Spring容器调用该Bean相关接口的调用
相同
: @Component
和 @Bean
都是注册Bean
区别
: @Component
是 被动
的方式,等待Spring容器扫描注解,将类注册为Bean,而 @Bean
则是 主动
的方式,主动地将类注册为Spring容器的Bean。
用法: @Component是通用写法,而@Bean通常用于引入外部类(从外部导入Jar包),又想将此类注册为Bean,但是又没有办法修改外部类的源代码,就可以利用@Bean将外部类注册成为Bean
@Configuration @ComponentScan public class Config { @Bean("customerBean") public Customer createCustomer() { Customer customer = new Customer(); return customer; } }复制代码
注意:依赖的注入,需要依赖已经成为Bean被Spring容器管理
@Ccomponent public class User{ @Autowired private Player player; }复制代码
@Component public class User { private final Player player; public User (Player player) { System.out.println("Config构造方法:" + player); this.player = player; } }复制代码
public class SimpleMovieLister { private MovieFinder movieFinder; public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } }复制代码
public class SimpleMovieLister { @Autowired private ApplicationContext context; private MovieFinder movieFinder; public void setMovieFinder(MovieFinder movieFinder) { this.movieFinder = movieFinder; } }复制代码
根据类型自动注入Bean,当有两个相同类型的候选者,优先注入有@Primary注解的类
@Configuration public class MovieConfiguration { @Bean @Primary public MovieCatalog firstMovieCatalog() { ... } @Bean public MovieCatalog secondMovieCatalog() { ... } }复制代码
在一个配置类里面,引入其他配置类
@Configuration @Import({TestConfig.class,DataSourceConfig.class}) public class ImportConfig { }复制代码
表明某个Bean需要依赖其他Bean
@Configuration public class TestConfig { @Bean("depend") public AccountRepository createJdbcAccountRepo() { return new JdbcAccountRepository(); } @Bean @DependsOn("depend") public TransferService createTransferSvc() { return new TransferServiceImpl(createJdbcAccountRepo()); } }复制代码
通过Environment可以获取JVM属性集
ApplicationContext ctx = new GenericApplicationContext(); Environment env = ctx.getEnvironment(); boolean containsMyProperty = env.containsProperty("my-property"); System.out.println("Does my environment contain the 'my-property' property? " + containsMyProperty);复制代码
获取Spring容器的环境对象,判断JVM是否存在my-property属性,如果存在则返回true,否则返回flase
System.getProperties()表示JVM系统属性集,System.getenv()表示系统环境变量集。可以用此功能来判断用户环境变量是否存在某个属性值,判断是否存在然后进行相应的操作
可以使用System.getProperties().put(key,value)来自动存入自定义JVM属性集
也可以使用@PropertySource,添加Property到Spring的Enviroment
public void testResourceLoader() throws IOException { // 本地资源可以使用类路径加载 Resource resource = ctx.getResource("https://www.baidu.com/img/bd_logo1.png"); Path path = Paths.get("C:/Users/admin/Desktop/java"); Files.createDirectories(path); //@formatter:off Files.copy( resource.getInputStream(), path.resolve(UUID.randomUUID().toString() + resource.getFilename()), StandardCopyOption.REPLACE_EXISTING ); //@formatter:on }复制代码
注意:使用此处的Paths和Resource需要使用JDK11以上