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组件。