Spring组件注册

Spring组件注册

@Bean

代码演示@Bean注解的使用

Dept

@NoArgsConstructor
@AllArgsConstructor
@Data
@ToString
@Component
public class Dept {
    private String id;
    private String name;
}

SpringConfig

@Configuration
public class SpringConfig {

    @Bean()
    public Dept dept(){
    return new Dept("001","财务部"); } }

通过@Bean注解,我们向IOC容器中注册了一个名称为dept的对象,Bean的默认名称为方法的 名称。 下面在启动类中测试从IOC容器中获取这个对象。

SpringDemoApplication

@SpringBootApplication
public class SpringDemoApplication {

    public static void main(String[] args) {
        //SpringApplication.run(SpringDemoApplication.class, args);

        // 返回 IOC 容器,使用注解配置,传入配置类
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        Dept dept = context.getBean(Dept.class);
        System.out.println(dept);
    }
}

控制台打印

Dept(id=001, name=财务部)

我们可以自己指定组件的名称

@Bean(value = "myDept")
public Dept dept(){
return new Dept("001","财务部");
}

启动类

ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
String[] beanNames = context.getBeanNamesForType(Dept.class);
Arrays.stream(beanNames).forEach(System.out::println);

控制台打印

myDept

@ComponentScan

使用@ComponentScan注解进行扫描。

修改配置类

@Configuration
@ComponentScan(value = "cn.xupengzhuang.springdemo")
public class SpringConfig {
}

在Controller、Service、Dao、pojo等包下的类上分别加上@Controller、@Service、 @Repository、@Component等注解

代码层次结构

启动类

// 返回 IOC 容器,使用注解配置,传入配置类
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
String[] beanDefinitionNames = context.getBeanDefinitionNames();
Arrays.stream(beanDefinitionNames).forEach(System.out::println);

控制台打印

springConfig
deptController
deptDao
dept
deptService

组件已经全部被扫描进去了,默认名称是类名字的首字母小写。

指定扫描策略1

@Configuration
@ComponentScan(value = "cn.xupengzhuang.springdemo",
    excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = Dept.class)
    })
public class SpringConfig {


}

除了@Controller注解标注的类以及Dept这个实体类,剩余的对象都将被扫描到IOC容器中。

控制台打印

springConfig
deptDao
deptService

指定扫描策略2

@Configuration
@ComponentScan(value = "cn.xupengzhuang.springdemo",
    includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = Controller.class),
        @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,classes = Dept.class)
    },useDefaultFilters = false)
public class SpringConfig {


}

会将@Controller注解标注的类、Dept类进行扫描。

控制台打印

springConfig
deptController
dept

指定扫描策略3-自定义

自定义扫描策略需要我们实现org.springframework.core.type.filter.TypeFilter接口

创建MyTypeFilter实现该接口

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();


        return className.contains("dept");
    }
}

SpringConfig

@Configuration
@ComponentScan(value = "cn.xupengzhuang.springdemo",
    excludeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM,classes = MyTypeFilter.class)},
        useDefaultFilters = false)
public class SpringConfig {


}
控制台打印
springConfig

@Scope

默认情况下,在Spring的IOC容器中每个组件都是单例的,即无论在任何地方注入多少次, 这些对象都是同一个。

配置类

@Configuration
public class SpringConfig {

@Bean(value = "myDept")
public Dept dept(){
return new Dept("001","财务部");
}

}

启动类

ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
Object myDept1 = context.getBean("myDept");
Object myDept2 = context.getBean("myDept");
System.out.println(myDept1 == myDept2);

控制台打印

true

在Spring中我们可以使用@Scope注解来改变组件的作用域:

  • singleton:单实例(默认),在Spring IOC容器启动的时候会调用方法创建对象 然后纳入到IOC容器中,以后每次获取都是直接从IOC容器中获取。
  • prototype:多实例,IOC容器启动的时候并不会去创建对象,而是在每次获取的 时候才会去调用方法创建对象。
  • request:一个请求对应一个实例。
  • session:同一个session对应一个实例。

@Lazy

懒加载是针对单例模式而言的,正如前面所说,IOC容器中的组件默认是单例的,容器启动 的时候会调用方法创建对象然后纳入到IOC容器中。

在DeptBean注册的地方加一行打印

@Configuration
public class SpringConfig {

    @Bean(value = "myDept")
    public Dept dept(){
        System.out.println("往IOC中注册Dept");
        return new Dept("001","财务部");
    }

}

启动类

ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
System.out.println("容器创建完毕");

控制台打印

往IOC中注册Dept
容器创建完毕

Dept修改为懒加载方式

@Configuration
public class SpringConfig {

    @Bean(value = "myDept")
    @Lazy
    public Dept dept(){
        System.out.println("往IOC中注册Dept");
        return new Dept("001","财务部");
    }

}

控制台打印

容器创建完毕

可以验证,在容器创建完成的时候,这个组件并没有加到容器中。 所以在单例模式中,IOC容器创建的时候,对于懒加载的组件,并不会马上去调用方法创建 对象并注册,只有第一次使用的时候才会调用方法创建对象并加入到容器中。

修改启动类进行验证

ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
System.out.println("容器创建完毕");
Object myDept2 = context.getBean("myDept");

控制台打印

容器创建完毕
往IOC中注册Dept

 可以发现在context.getBean("myDept");代码执行之后,才会往IOC容器中注册myDept组件。

 

原文地址:https://www.cnblogs.com/beanbag/p/13374761.html