Spring需要使用的组件配置pom.xml
0.注解添加组件的四种方法
- 1)@Bean: [导入第三方的类或包的组件],比如Person为第三方的类, 需要在我们的IOC容器中使用
- 2)包扫描+组件的标注注解(@ComponentScan: @Controller, @Service @Repository @ Component),一般是针对 我们自己写的类,使用这个
- 3)@Import:[快速给容器导入一个组件] 注意:@Bean有点简单
3-a)@Import(要导入到容器中的组件):容器会自动注册这个组件,bean 的 id为全类名
3-b)ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
3-c)ImportBeanDefinitionRegistrar:可以手动添加组件到IOC容器, 所有Bean的注册可以使用BeanDifinitionRegistry
写JamesImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口即可 - 4)使用Spring提供的FactoryBean进行注册
1.基于XML配置
使用bean标签注册组件Person.java(配置文件beans.xml参考):
测试类MainTest1.java
public static void main(String args[]){
//把beans.xml的类加载到容器
ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml");
//从容器中获取bean
Person person = (Person) app.getBean("person");
System.out.println(person);
}
结果:
Person [name=wz, age=19]
2.@Configuration + @Bean
配置类MainConfig等价于配置文件beans.xml:
//配置类====配置文件
@Configuration
public class MainConfig {
//给容器中注册一个bean, 类型为返回值的类型,
@Bean("abcPerson")
// @Bean
public Person person01(){
return new Person("wz",20);
}
}
测试类MainTest2.java
public class MainTest2 {
public static void main(String args[]){
ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
//从容器中获取bean
Person person = (Person) app.getBean("abcPerson");
System.out.println(person);
String[] namesForBean = app.getBeanNamesForType(Person.class);
for(String name:namesForBean){
System.out.println(name);
}
}
}
结果:
Person [name=wz, age=20]
abcPerson
2.1 @Scope (单实例、多实例)
配置类Ch3MainConfig.java
@Configuration
public class Ch3MainConfig {
//给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
/*
* prototype:多实例: IOC容器启动的时候,IOC容器启动并不会去调用方法创建对象, 而是每次获取的时候才会调用方法创建对象
* singleton:单实例(默认):IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿(大Map.get)的同一个bean
* request: 主要针对web应用, 递交一次请求创建一个实例
* session:同一个session创建一个实例
*/
@Scope("prototype")
@Bean
public Person person(){
return new Person("wz",20);
}
}
Scope测试类Ch3Test.java
public class Ch3Test {
@Test
public void test01(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch3MainConfig.class);
String[] names = app.getBeanDefinitionNames();
for(String name:names){
System.out.println(name);
}
//从容器中分别取两次person实例, 看是否为同一个bean
Object bean1 = app.getBean("person");
Object bean2 = app.getBean("person");
System.out.println(bean1 == bean2);
}
}
2.2 @lazy (控制单例bean什么时候创建对象)
lazy配置类Ch4MainConfig.java
@Configuration
public class Ch4MainConfig {
//给容器中注册一个bean, 类型为返回值的类型, 默认是单实例
/*
* 懒加载: 主要针对单实例bean:默认在容器启动的时候创建对象
* 懒加载:容器启动时候不创建对象, 仅当第一次使用(获取)bean的时候才创建被初始化
*/
@Lazy
@Bean
public Person person(){
System.out.println("给容器中添加person.......");
return new Person("james",20);
}
}
lazy测试类Ch4Test.java
public class Ch4Test {
@Test
public void test01(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch4MainConfig.class);
System.out.println("IOC容器创建完成........");
app.getBean("person");//执行获取的时候才创建并初始化bean
}
}
2.3 @Conditional
Conditional配置类Ch5MainConfig.java
@Configuration
public class Ch5MainConfig {
@Bean("person")
public Person person(){
System.out.println("给容器中添加person.......");
return new Person("person",20);
}
@Conditional(WinCondition.class)
@Bean("lison")
public Person lison(){
System.out.println("给容器中添加lison.......");
return new Person("Lison",58);
}
@Conditional(LinCondition.class)
@Bean("james")//bean在容器中的ID为james, IOC容器MAP, map.put("id",value)
public Person james(){
System.out.println("给容器中添加james.......");
return new Person("james",20);
}
}
判断操作系统是否是Windows的类WinCondition.java
public class WinCondition implements Condition {
/*
*ConditionContext: 判断条件可以使用的上下文(环境)
*AnnotatedTypeMetadata: 注解的信息
*
*/
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO 是否为WINDOW系统
//能获取到IOC容器正在使用的beanFactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//获取当前环境变量(包括我们操作系统是WIN还是LINUX??)
Environment environment = context.getEnvironment();
String os_name = environment.getProperty("os.name");
if(os_name.contains("Windows")){
return true;
}
return false;
}
}
Conditional测试类Ch5Test.java
public class Ch5Test {
@Test
public void test01(){
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch5MainConfig.class);
System.out.println("IOC容器创建完成........");
}
}
3.@ComponentScan
整个ComponentScan的各种用法参考ch2
ComponentScan的测试类Ch2Test.java
配置类Cap2MainConfig.java
作用:指定要扫描的包,并且可以定制扫描时的过滤规则
- useDefaultFilters默认是true,扫描所有组件,要改成false,使用自定义扫描范围
- @ComponentScan value:指定要扫描的包
- excludeFilters = Filter[] 指定扫描的时候按照什么规则排除那些组件
- includeFilters = Filter[] 指定扫描的时候只需要包含哪些组件
- 扫描规则:
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照给定的类型;比如按OrderController.class类型
FilterType.ASPECTJ:使用ASPECTJ表达式
FilterType.REGEX:使用正则指定
FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口,参考WzTypeFilter.java
@Configuration
//@Controller @Service @Repository @Component
//@ComponentScan(value="com.wangzhen.ch2")
//@ComponentScan(value="com.wangzhen.ch2", includeFilters={
// @ComponentScan.Filter(type=FilterType.ANNOTATION, classes={Controller.class})
//}, useDefaultFilters=false)
//@ComponentScan(value="com.wangzhen.ch2", excludeFilters={
// @ComponentScan.Filter(type=FilterType.ANNOTATION, classes={Controller.class})
//}, useDefaultFilters=true)
//@ComponentScan(value="com.wangzhen.ch2", includeFilters={
// @ComponentScan.Filter(type=FilterType.ASSIGNABLE_TYPE, classes={OrderController.class})
//}, useDefaultFilters=false)
@ComponentScan(value="com.wangzhen.ch2", includeFilters={
@ComponentScan.Filter(type=FilterType.CUSTOM, classes={WzTypeFilter.class})
}, useDefaultFilters=false)
public class Cap2MainConfig {
//给容器中注册一个bean, 类型为返回值的类型,
@Bean
public Person person01(){
return new Person("james",20);
}
}
4.@Import
Import配置类Ch6MainConfig.java
@Configuration
@Import(value = { Dog.class, Cat.class, JamesImportSelector.class,JamesImportBeanDefinitionRegistrar.class })
public class Ch6MainConfig {
/*
* 给容器中注册组件的方式
* 1,@Bean: [导入第三方的类或包的组件],比如Person为第三方的类, 需要在我们的IOC容器中使用
* 2,包扫描+组件的标注注解(@ComponentScan: @Controller, @Service @Repository @ Component),一般是针对 我们自己写的类,使用这个
* 3,@Import:[快速给容器导入一个组件] 注意:@Bean有点简单
* a,@Import(要导入到容器中的组件):容器会自动注册这个组件,bean 的 id为全类名
* b,ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
* c,ImportBeanDefinitionRegistrar:可以手动添加组件到IOC容器, 所有Bean的注册可以使用BeanDifinitionRegistry
* 写JamesImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口即可
* 4,使用Spring提供的FactoryBean(工厂bean)进行注册
*
*
*/
//容器启动时初始化person的bean实例
@Bean("person")
public Person persond(){
System.out.println("aaaaaaaaaaaa");
return new Person("james",20);
}
//@Bean("person1")
public Person persona(int a){
System.out.println("bbbbbbbbbbb");
return new Person("james",20);
}
@Bean
public JamesFactoryBean jamesFactoryBean(){
return new JamesFactoryBean();
}
}
实现ImportSelector接口注册组件
public class JamesImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata){
//返回全类名的bean
//return null; 不要返回null
// return new String[]{};
return new String[]{"com.wangzhen.ch6.bean.Fish","com.wangzhen.ch6.bean.Tiger"};
}
}
实现接口ImportBeanDefinitionRegistrar注册组件
public class JamesImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/*
*AnnotationMetadata:当前类的注解信息
*BeanDefinitionRegistry:BeanDefinition注册类
* 把所有需要添加到容器中的bean加入;
* @Scope
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean bean1 = registry.containsBeanDefinition("com.wangzhen.ch6.bean.Dog");
boolean bean2 = registry.containsBeanDefinition("com.wangzhen.ch6.bean.Cat");
//如果Dog和Cat同时存在于我们IOC容器中,那么创建Pig类, 加入到容器
//对于我们要注册的bean, 给bean进行封装,
if(bean1 && bean2){
RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class);
registry.registerBeanDefinition("pig", beanDefinition);
}
}
}
Import测试类
public class Ch6Test {
@Test
public void test01() {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch6MainConfig.class);
System.out.println("IOC容器创建完成........");
String[] beanDefinitionNames = app.getBeanDefinitionNames();
for (String name : beanDefinitionNames) {
System.out.println(name);
}
}
}
5.FactoryBean
FactoryBean配置类Ch6MainConfig.java
@Bean
public JamesFactoryBean jamesFactoryBean(){
return new JamesFactoryBean();
}
JamesFactoryBean类实现FactoryBean
public class JamesFactoryBean implements FactoryBean {
@Override
public Monkey getObject() throws Exception {
// TODO Auto-generated method stub
return new Monkey();
}
@Override
public Class> getObjectType() {
// TODO Auto-generated method stub
return Monkey.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
FactoryBean测试类
public class Ch6Test {
@Test
public void test01() {
AnnotationConfigApplicationContext app = new AnnotationConfigApplicationContext(Ch6MainConfig.class);
System.out.println("IOC容器创建完成........");
Object bean1 = app.getBean("jamesFactoryBean");
Object bean2 = app.getBean("jamesFactoryBean");//取Money
System.out.println("bean1的类型=" + bean1.getClass());
System.out.println(bean1 == bean2);
Object bean3 = app.getBean("&jamesFactoryBean");
System.out.println("bean3的类型=" + bean3.getClass());
- FactoryBean注册组件的源码解析后可知
容器调用getObject()返回对象,把对象放到容器中;
getObjectType()返回对象类型
isSingleton()是否单例进行控制
a)默认获取到的是工厂bean调用getObject创建的对象
b)要获取工厂Bean本身,需要在id前加个 &jamesFactoryBean
参考
- 1)享学课堂James老师笔记