1. 程式人生 > 實用技巧 >Spring元件註冊

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