一. 组件注册
1. 给容器中注册组件
xml方式
-
创建一个实体类(构造方法等省略)
public class Person { private String name; private Integer age; }
-
resources资源目录下创建xml文件
- 利用bean标签注册一个组件
- 得到id,方便从容器中获取该bean
- 使用property进行属性赋值
<bean id="person" class="com.lcy.bean.Person"> <property name="name" value="诸葛亮"/> <property name="age" value="18"/> </bean>
-
创建一个测试类
- 传入配置文件的位置,返回IOC容器
- 根据id获取值
@Test public void t1() { // new一个CPXAC传入配置文件的位置,返回IOC容器applicationContext ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml"); // 根据id获取组件 Person person = (Person) applicationContext.getBean("person"); System.out.println(person); }
-
控制台输出
Person{name='诸葛亮', age=18}
配置类方式
-
实体类不变
-
创建一个配置类
// 配置类==配置文件 @Configuration // 告诉Spring这是一个配置类 public class MainConfig { // 给容器注册一个Bean,类型为返回值的类型,id默认是方法名(可以直接指定value方法值) @Bean public Person person() { return new Person("刘备",19); } }
-
测试类(入口代码省略)
@Test public void t2() { // new一个AnnotationConfigApplicationContext,传入配置文件,得到IOC容器 ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); // 根据类型获取值 Person bean = applicationContext.getBean(Person.class); System.out.println("根据类型获取"+bean); // 根据Id获取,默认Id就是方法名 String[] namesForType = applicationContext.getBeanNamesForType(Person.class); for (String name : namesForType) { System.out.println("获取该组件的id是"+name); } }
-
控制台
根据类型获取Person{name='刘备', age=19} 获取该组件的id是person
2. 自动扫描组件与指定扫描规则
xml文件扫描时
-
在配置文件中配置
- 只要指定包下的标注了Controller,Service,Repository,Component就会被扫描到
<context:component-scan base-package="com.lcy"/>
配置文件包扫描
-
在配置类上加上注解@ComponentScan
// 配置类==配置文件 @ComponentScan(value = "com.lcy") // 包扫描 @Configuration // 告诉Spring这是一个配置类 public class MainConfig { @Bean public Person person() { return new Person("刘备",19); } }
-
测试
- 获取当前IOC中所有组件的名字
@Test public void t3() { ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig.class); // 获取容器中所有组件的名字 String[] names = ioc.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } }
-
控制台
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig personController personDao personService person
-
excludeFilters(排除)
-
排除Controller和Service标注的组件
```Java
@ComponentScan(value = "com.lcy",excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})})
@Configuration
public class MainConfig {
@Bean
public Person person() {
return new Person("刘备",19);
}
}
```
-
控制台
- 与上次输出比较,过滤规则起作用了
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig personDao person
-
includeFilters(只包含)
-
恰恰相反,需要禁用掉默认过滤规则才能生效
-
useDefaultFilters = false
-
-
只要Controller和Service标注的组件
@ComponentScan(value = "com.lcy",includeFilters = { @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})}, useDefaultFilters = false) @Configuration public class MainConfig { @Bean public Person person() { return new Person("刘备",19); } }
-
控制台
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig personController personService person
-
扫描规则
@ComponentScan(value = "com.lcy",includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class}),
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = PersonDao.class)},
useDefaultFilters = false)
// @ComponentScan value:指定要扫描的包
// includeFilters = Filter[]:指定扫描时只需要包含哪些组件
// excludeFilters = Filter[]:指定扫描时按照规则排除组件
// FilterType.ANNOTATION:按照注解(常用)
// FilterType.ASSIGNABLE_TYPE:按照类型(常用)所有的其子类实现类都会被加载进来
// FilterType.ASPECTJ:按照ASPECTJ表达式
// FilterType.REGEX:按照正ava则
// FilterType.CUSTOM:按照自定义规则(需要TypeFilter的实现类)
-
自定义过滤规则
-
创建一个类实现TypeFilter接口
public class MyTypeFilter implements TypeFilter { /** * * @param metadataReader 读取到的当前正在扫描类的信息 * @param metadataReaderFactory 可以读取到其他任何类的信息 * @return * @throws IOException */ @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // 获取当前类注解的信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); // 获取当前正在扫描类的类信息(比如实现了什么接口,什么类型) ClassMetadata classMetadata = metadataReader.getClassMetadata(); // 获取当前类资源(类的路径) Resource resource = metadataReader.getResource(); // 获取当前正在处理类的类名 String className = classMetadata.getClassName(); System.out.println("----->类名"+className); // 如果类名中包含Dao,则返回true,匹配成功放行 if (className.contains("Dao")) { return true; } return false; } }
-
配置类进行设置
@Configuration @ComponentScan(value = "com.lcy",includeFilters = { @ComponentScan.Filter(type = FilterType.CUSTOM,classes = MyTypeFilter.class)}, // 自定义规则 useDefaultFilters = false) public class MainConfig { @Bean public Person person() {java return new Person("刘备",19); } }
-
控制台
----->类名com.lcy.bean.Person ----->类名com.lcy.config.MyTypeFilter ----->类名com.lcy.controller.PersonController ----->类名com.lcy.dao.PersonDao ----->类名com.lcy.service.PersonService org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig personDao person Process finished with exit code 0
-
3. @Scope设置作用域
默认单例
-
配置类
@Configuration public class MainConfig2 { // 默认为单例 /** * prototype:多实例的 * singleton:单实例的(默认值)ioc容器每次调用方法创建对象放到ioc容器中 * 之后的每一次获取都是直接从容器中拿 * request: 同一次请求创建一个实例(需要web环境) * session: 同一个Session创建一个实例(需要web环境) */ @Scope @Bean public Person person() { System.out.println("给容器添加Person"); return new Person("周瑜",20); } }
-
测试类
@Test public void t4() { ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class); // 根据Id来获取 Person bean1 = (Person) ioc.getBean("person"); Person bean2 = (Person) ioc.getBean("person"); // 默认单例,判断两个对象是否相等 System.out.println(bean1 == bean2); // true }
-
控制台
给容器添加Person IOC容器创建完成 true
多例
-
配置类
@Configuration public class MainConfig2 { @Bean /** * prototype:多实例的:ioc启动并不会创建对象放在容器 * 每次获取时才会调用方法创建对象 */ @Scope("prototype") public Person person() { System.out.println("给容器添加Person"); return new Person("周瑜",20); } }
-
测试类
@Test public void t4() { ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class); System.out.println("IOC容器创建完成"); // 根据Id来获取 Person bean1 = (Person) ioc.getBean("person"); Person bean2 = (Person) ioc.getBean("person"); // 修改为prototype,判断两个对象是否相等 System.out.println(bean1 == bean2); // false }
-
控制台
IOC容器创建完成 给容器添加Person 给容器添加Person false
懒加载
-
配置类(未启动懒加载)
@Configuration public class MainConfig2 { // 默认为单例 @Bean /** * singleton:单实例的(默认值)ioc容器每次调用方法创建对象放到 ioc容器中 * 懒加载: * 单实例Bean:默认在容器启动时创建对象 * 懒加载:容器启动时不创建对象,第一次(使用)获取Bean创建 对象并初始化 * */ @Scope public Person person() { System.out.println("给容器添加Person"); return new Person("周瑜",20); } }
-
测试类
@Test public void t4() { ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class); System.out.println("IOC容器创建完成"); }
-
控制台
- 在IOC启动的时候就创建完成了
给容器添加Person IOC容器创建完成
-
启用懒加载@Lazy
-
配置类
@Configuration public class MainConfig2 { @Bean @Scope @Lazy public Person person() { System.out.println("给容器添加Person"); return new Person("周瑜",20); } }
-
测试类与控制台(未使用Bean)
@Test public void t4() { ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class); System.out.println("IOC容器创建完成"); }
IOC容器创建完成
-
测试类与控制台(使用Bean)
- 使用Bean时才会创建,并且只会创建一次
@Test public void t4() { ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class); System.out.println("IOC容器创建完成"); // 根据Id来获取 Person bean1 = (Person) ioc.getBean("person"); Person bean2 = (Person) ioc.getBean("person"); }
IOC容器创建完成 给容器添加Person
-
4. @Conditional按照条件注册bean
-
若放在类上,必须满足条件,此类中的bean注册才能生效
-
条件:
- 如果是windows,给容器中注册windows
- 如果是Linux,给容器中注册Linux
-
配置类
/** * @return * @Conditional({}) :按照一定条件进行判断,满足条件给容器中注册 bean */ @Conditional({WindowsCondition.class}) // 放在类上,必须满足条件,此类中的bean注册才能生效 @Bean("Windows") public Person person1() { return new Person("Windows", 22); } @Bean("Linux") @Conditional({LinuxCondition.class}) public Person person2() { return new Person("Linux", 20); }
-
分别创建两个类实现Condition接口
// 判断是否为Linux系统 public class LinuxCondition implements Condition { @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { Environment environment = conditionContext.getEnvironment(); String property = environment.getProperty("os.name"); if (property.contains("Linux")) { return true; } return false; }java }
// 判断是否为Windows系统 public class WindowsCondition implements Condition { /** * * @param conditionContext 判断条件能使用的上下文环境 * @param annotatedTypeMetadata 注释信息 * @return */ @Override public boolean matches(ConditionContext conditionContext, AnnotatedTypeMetadata annotatedTypeMetadata) { // 1.能获取到IOC使用的beanfactory ConfigurableListableBeanFactory beanFactory = conditionContext.getBeanFactory(); // 2.获取类加载器 ClassLoader classLoader = conditionContext.getClassLoader(); // 3.获取当前环境信息 Environment environment = conditionContext.getEnvironment(); // 4.获取到bean定义的注册类 BeanDefinitionRegistry registry = conditionContext.getRegistry(); // 可以判断容器中的bean注册情况,也可以给容器中注册bean boolean person = registry.containsBeanDefinition("person"); // 获取操作系统 String property = environment.getProperty("os.name"); // 判断是否为Windows系统 if (property.contains("Windows")){ return true; } return false; } }
-
测试类
@Test public void t5() { ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig2.class); String[] beanNamesForType = ioc.getBeanNamesForType(Person.class); for (String name : beanNamesForType) { System.out.println(name); } Map<String, Person> personMap = ioc.getBeansOfType(Person.class); System.out.println(personMap); }
-
控制台
- 因为是Windows操作系统,所以Linux并没有注册进来
- person是之前已注册的
person Windows 给容器添加Person {person=Person{name='周瑜', age=20}, Windows=Person{name='Windows', age=22}}
5. @Import导入组件
@Import
-
创建一个实体类
public class Color { }
-
配置类加入类名@Import
@Configuration @Import(Color.class) //@Import({Color.class, Person.class}) 也可以导多个类 public class MainConfig3 { /** * 给容器中注册组件: * 1.包扫描+组件标注注解(@Controller,@Service,@Repository,@Component)[局限于自己创建的类] * 2.@Bean[导入的第三方包里面的组件] * 3.@Import[快速给容器中导入一个组件] * 1.@Improt(要导入容器的组件),容器会自动注册这个组件,id默认是全类名 */ }
-
测试类
@Test public void t6() { ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig3.class); String[] names = ioc.getBeanDefinitionNames(); for (String name : names) { System.out.println(name); } }
-
控制台
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig3 com.lcy.bean.Color
ImportSelector接口
-
创建一个类实现ImportSelector接口
// 自定义逻辑返回需要导入的组件 public class MyImportSelector implements ImportSelector { /** * 返回值就是要导入到容器中的组件全类名 * @param annotationMetadata :当前标注@Import注解类的所有注解信息 * @return */ @Override public String[] selectImports(AnnotationMetadata annotationMetadata) { // 放入需要注册组件的全类名 return new String[]{"com.lcy.bean.Red","com.lcy.bean.Blue"}; } }
-
配置类
@Configuration @Import({Color.class, MyImportSelector.class}) public class MainConfig3 { /** * ImportSelector:返回需要导入的组件的全类名数组 * 创建一个类实现ImportSelector接口,在@Import上导入 */ }
-
测试(代码如上不变)控制台
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig3 com.lcy.bean.Color com.lcy.bean.Red com.lcy.bean.Blue
ImportBeanDefinitionRegistrar接口
-
创建新的实体类
public class RainBow { }
-
配置类
@Configuration @Import({Color.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) public class MainConfig3 { /** * ImportBeanDefinitionRegistrar:手动注册bean到容器 */ }
-
创建一个类实现ImportBeanDefinitionRegistrar接口
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * * @param importingClassMetadata:当前类的注解信息 * @param registry : 把所有需要添加到容器中的bean, * 调用registry.registerBeanDefinition手工注册进来 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { // 指定bean的定义信息(Bean的类型) RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class); // 注册一个bean,指定bean名 registry.registerBeanDefinition("rainBow",beanDefinition); } }
-
测试类(代码不变)与控制台
org.springframework.context.annotation.internalConfigurationAnnotationProcessor org.springframework.context.annotation.internalAutowiredAnnotationProcessor org.springframework.context.annotation.internalCommonAnnotationProcessor org.springframework.context.event.internalEventListenerProcessor org.springframework.context.event.internalEventListenerFactory mainConfig3 com.lcy.bean.Color com.lcy.bean.Red com.lcy.bean.Blue rainBow
FactoryBean工厂Bean
-
配置类
/** * .使用Spring提供的FactoryBean(工厂Bean) * 1.默认获取到的是工厂Bean调用getObject创建的对象 * 2.要获取工厂Bean本身,则在id前加一个& */ @Bean // 虽然注册的是YellowFactoryBean,但实际上是Yellow public YellowFactoryBean yellowFactoryBean() { return new YellowFactoryBean(); }
-
创建一个实体类
public class Yellow { }
-
创建一个类实现FactoryBean接口
public class YellowFactoryBean implements FactoryBean<Yellow> { // 返回一个Yellow对象,这个对象会添加到容器中 @Override public Yellow getObject() throws Exception { System.out.println("YellowFactoryBean。。。。。getObject"); return new Yellow(); } // 返回对象的类型 @Override public Class<?> getObjectType() { return Yellow.class; } // 控制是否单例:true为单例; 在容器中保存一份 // false:多例;每次获取都会创建一个新的bean,获取的时候会调用getObject @Override public boolean isSingleton() { return true; } }
-
测试类
@Test public void t6() { ApplicationContext ioc = new AnnotationConfigApplicationContext(MainConfig3.class); // 工厂Bean获取的是调用gerObject创建的对象 Object bean = ioc.getBean("yellowFactoryBean"); System.out.println("bean的类型="+bean.getClass()); // 若想获取工厂Bean的本身则加& Object bean1 = ioc.getBean("&yellowFactoryBean"); System.out.println("bean的类型="+bean1); }
-
控制台
YellowFactoryBean。。。。。getObject bean的类型=class com.lcy.bean.Yellow bean的类型=com.lcy.condition.YellowFactoryBean@1f0f1111