Spring元件註冊
阿新 • • 發佈:2020-07-25
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元件。