Spring IOC(Inversion of Control ) 控制反转是一种思想,并不是 Spring 所特有的,而 DI 依赖注入是这种思想的具体实现方案。
@Configuration //配置类==配置文件
- @Bean
给容器中注册一个Bean;类型为返回值的类型,id默认是方法名,可通过该注解指定
@Bean
public Person person(){
return new Person("zhangsan", 20);
}
@Bean("person01") // 指定id
public Person person(){
return new Person("zhangsan", 20);
}
- @ComponentScan
加在配置类上,扫描指定包下所有类,默认加载标注了@Controller、@Service、@Repository、@Component
@ComponentScan("org.chm")
excludeFilters:指定扫描时按照什么规则排除哪些组件
@ComponentScan(value = "org.chm", excludeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
})
```java
includeFilters:指定扫描时只需要包含哪些组件,需要结合useDefaultFilters设置为false,静止默认加载规则
```java
@ComponentScan(value = "org.chm", includeFilters = {
@ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class, Service.class})
}, useDefaultFilters = false)
Java 8 开始新增@Repeatable注解,允许同一个注解可以使用多次,如今Java 8 环境可在一个配置类上多次使用@ComponentScan注解,8 之前可以使用@ComponentScans。
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
...
}
过滤规则:
- FilterType.ANNOTATION:按照注解过滤
- ASSIGNABLE_TYPE:按照给定的类型过滤(包含子类)
- ASPECTJ:使用ASPECTJ表达式过滤
- REGEX:使用正则
- CUSTOM:按照自定义规则过滤
@ComponentScan(value = "org.chm", includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
}, useDefaultFilters = false)
@Configuration
public class PersonConfig {
...
}
public class MyTypeFilter implements TypeFilter {
/**
*
* @param metadataReader:读取到的当前正在扫描的类的信息
* @param metadataReaderFactory:可以获取到其他任何类信息
*/
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
metadataReader.getAnnotationMetadata();
//获取当前类注解的信息
metadataReader.getAnnotationMetadata();
//获取当前类的类信息
metadataReader.getClassMetadata();
//获取当前类资源(类的路径)
metadataReader.getResource();
ClassMetadata classMetadata = metadataReader.getClassMetadata();
System.out.println("--> "+classMetadata.getClassName());
return false;
}
}
-
@Scope 控制作用域
- singleton 单实例(默认值):ioc容器在启动时调用方法创建对象放入ioc容器中,以后每次获取就是直接从容器中拿。
- prototype 多实例:ioc容器在启动时不会调用方法创建对象放入容器,每次获取(getBean)的时候才哈调用方法创建对象。
- request 同一次请求创建一个实例
- session 同一个session创建一个实例
-
@Lazy
懒加载,针对单实例bean(默认在容器启动时创建),懒加载就是在容器启动时不创建对象,而是第一次使用(获取)Bean时创建对象,并初始化。 -
@Conditional SpringBoot中使用较多
按条件给容器注册bean,可以放在类上或方法上使用,放在类上表示满足当前条件,这个类中配置的索引bean注册才能生效(统一管理)
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
Environment environment = context.getEnvironment();
String name = environment.getProperty("os.name");
if (name.contains("Linux"))
{
return true;
}
return false;
}
}
public class WindowCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// 获取到ioc使用的beanfactory
context.getBeanFactory();
// 获取bean定义的注册类
context.getRegistry();
// 获取当前环境信息
Environment environment = context.getEnvironment();
String name = environment.getProperty("os.name");
if (name.contains("Windows"))
{
return true;
}
return false;
}
}
@Configuration //告诉Spring这是一个配置类,配置类==配置文件
@ComponentScan(value = "org.chm", includeFilters = {
@ComponentScan.Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})
}, useDefaultFilters = false)
public class PersonConfig {
//给容器中注册一个Bean;类型为返回值的类型,id默认是方法名,可通过该注解指定
@Bean
public Person person(){
return new Person("zhangsan", 20);
}
@Bean("bill")
@Conditional({WindowCondition.class})
public Person person01()
{
return new Person("Bill Gates", 62);
}
@Bean("linus")
@Conditional({LinuxCondition.class})
public Person person02()
{
return new Person("Linus", 48);
}
}
给容器中注册组件的四种方式:
1)包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
2)@Bean:导入的第三方包里面的组件)
3)@Import 快速给容器导入一个组件
- @Import(Color.class) 容器中会自动注册这个组件,id就是全类名。
- @Import+ImportSelector(SpringBoot中使用较多)
- @Import+ImportBeanDefinitionRegistrar 收到注册bean到容器中
// 自定义四逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
// 返回值就是要导入到容器中的组件全类名
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"org.chm.bean.Red", "org.chm.bean.Yellow"};
}
}
@Import({Blue.class, MyImportSelector.class})
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* @param importingClassMetadata 当前类的注解信息
* @param registry 调用BeanDefinitionRegistry.registerBeanDefinition方法手工注册到容器中
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
boolean definition = registry.containsBeanDefinition("org.chm.bean.Blue");
boolean definition2 = registry.containsBeanDefinition("org.chm.bean.Yellow");
if (definition && definition2)
{
registry.registerBeanDefinition("rainBow", new RootBeanDefinition(RainBow.class));
}
}
}
@Import({Blue.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
4)使用Spring提供的FactoryBean(工厂Bean);
- 默认获取到的是工厂bean调用getObject创建的对象
- 要获取工厂Bean本身,我们需要给id前面加一个&符号
public class ColorFactoryBean implements FactoryBean<Color> {
@Override
public Color getObject() throws Exception {
return new Color();
}
@Override
public Class<?> getObjectType() {
return Color.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
// 配置类中加入
@Bean
public ColorFactoryBean colorFactoryBean()
{
return new ColorFactoryBean();
}
测试类
public class MainTest {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(PersonConfig.class);
// Person person = context.getBean(Person.class);
// System.out.println(person);
// String[] names = context.getBeanNamesForType(Person.class);
// Arrays.asList(names).forEach(System.out::println);
String[] beanNames = context.getBeanDefinitionNames();
Arrays.asList(beanNames).forEach(System.out::println);
Object object = context.getBean("colorFactoryBean");
System.out.println("类型:"+object.getClass().getName());
}
}
本文基于尚硅谷Spring教学视频,在此感谢。