小白學習後端開發之Spring框架註解大全(一)

一、Spring 初次嘗試

1、通過xml形式配置IOC容器Bean

在Project下面找到一個resources 文件夾創建一個beans.xml (xml的文件名隨意)。如下,把你需要加載的bean 插入到bean節點下面。定義id 和 class類。當application被創建的時候,他就會去掃對應的xml文件,將這裏定義的bean加載到IOC容器。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="person" class="lsn01.cap01.Person">
        <property name="name" value="jack"/>
        <property name="age" value="19"/>
    </bean>
</beans>

測試方式:(xml形式 需要使用ClassPathXmlApplicationContext)

ApplicationContext appxml = new ClassPathXmlApplicationContext("beans.xml");
Person person = appxml.getBean("person", Person.class);
System.out.println(person.toString());

2、通過註解的形式加載bean

註解1:@Configuration 作用於類,被這個註解標註的類可以理解成beans.xml
註解2:@Bean 作用於方法,主要作用往IOC容器中註冊一個Bean, 值是id 返回值是Bean的類型

@Configuration
public class MainConfig {

    @Bean("springPerson")
    public Person getPerson(){
        return new Person("spring",17);
    }
}

測試方式:

ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class);
Person springPerson = (Person) app.getBean("springPerson");
System.out.println(springPerson.toString());
String[] beanNamesForType = app.getBeanNamesForType(Person.class);
for (String name : beanNamesForType) {
    System.out.println(name);
}

作爲一個小白,第一次看到這樣的操作註解,並不知道這裏有什麼作用。

Spring Bean和Configuration 升級

1、ComponentScan 定義掃描組件規則

通過註解我們可以定義配置類也就是Configuration可以掃描到那些類。以MVC爲例我一般會定義 Controller、Service、Dao。 所以我們會定義很多這些相關的類,但是並不是所有類都需要加載到IOC容器。所謂Component 其實Controller、Service、Dao(Repository) 都是Component沒有本質上的區別,就是一個類,註解被標記的時候,表明它的作用,起到一個提示作用。
如下目錄結構:

-test2
-controller
OrderControlller.java
-dao
OrderDao.java
-service
OrderService.java

@Controller
public class OrderControlller {
}

@Repository
public class OrderDao {
}

@Service
public class OrderService {
}

接下來定義配置類

@Configuration
@ComponentScan(value = {"lsn01.cap02"}, includeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION, classes = {Controller.class})
}, useDefaultFilters = false)
public class Cap01MainConfig {
}

定義測試方式:

@Test
public void testComponentScan(){
    ApplicationContext app = new AnnotationConfigApplicationContext(Cap02MainConfig.class);
    String[] beanDefinitionNames = app.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println("beanDefinitionName = "+beanDefinitionName);
    }
}

ComponentScan註解主要屬性,

1、value 配置掃碼的包路徑String[] value() default {}

2、includeFilters 包含哪些Filter。 可以通過定義type 和classs 指定哪些可以被掃描到。
如:@ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class})
打印結果:

beanDefinitionName = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalCommonAnnotationProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerFactory
beanDefinitionName = cap02MainConfig
beanDefinitionName = orderControlller
beanDefinitionName = orderDao
beanDefinitionName = orderService

顯然並沒有起到一個過濾效果,依然把所有的組件全部掃描進來,而我們需要的只是包含Controller註解的類。
原因在於 useDefaultFilters = false 設置,關閉到默認的Filters

beanDefinitionName = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalCommonAnnotationProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerFactory
beanDefinitionName = cap02MainConfig
beanDefinitionName = orderControlller

3、excludeFilters 不包含哪些Filters 注意:如果使用這個註解就不需要將設置成true 否則將不會掃描任何組件
如:

excludeFilters =
                @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Service.class}),
        useDefaultFilters = false

打印結果:

beanDefinitionName = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalCommonAnnotationProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerFactory
beanDefinitionName = cap02MainConfig

4、自定義Filters

public class CustomFilter implements TypeFilter {

    public boolean match(MetadataReader metadataReader,
                         MetadataReaderFactory metadataReaderFactory) throws IOException {
        //當前掃描類的註解信息
        AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
        Set<String> annotationTypes = annotationMetadata.getAnnotationTypes();
        for (String annotationType : annotationTypes) {
            System.out.println("annotationType : "+annotationType);
        }
        //當前掃描類的類的信息
        ClassMetadata classMetadata = metadataReader.getClassMetadata();
        String className = classMetadata.getClassName();
        System.out.println("classMetadata className = "+className);
        //當前掃描類的資源
        Resource resource = metadataReader.getResource();
        String filename = resource.getFilename();
        System.out.println("filename = "+filename);

        //返回true就是包含,false就是不包含
        return false;
    }
}

相關的自定義可以根據上面的三種信息定義屬於的結果邏輯返回。

打印結果

classMetadata className = lsn01.cap02.config.CustomFilter
filename = CustomFilter.class
annotationType : org.springframework.stereotype.Controller
classMetadata className = lsn01.cap02.controller.OrderControlller
filename = OrderControlller.class
annotationType : org.springframework.stereotype.Repository
classMetadata className = lsn01.cap02.dao.OrderDao
filename = OrderDao.class
annotationType : org.springframework.stereotype.Service
classMetadata className = lsn01.cap02.service.OrderService
filename = OrderService.class
beanDefinitionName = org.springframework.context.annotation.internalConfigurationAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalAutowiredAnnotationProcessor
beanDefinitionName = org.springframework.context.annotation.internalCommonAnnotationProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerProcessor
beanDefinitionName = org.springframework.context.event.internalEventListenerFactory
beanDefinitionName = cap02MainConfig

1、從打印結果上看我們可以看到 最先掃描的是CustomFilter
2、FilterType.ANNOTATION:按照註解
FilterType.ASSIGNABLE_TYPE:按照給定的類型;比如按BookService類型
FilterType.ASPECTJ:使用ASPECTJ表達式
FilterType.REGEX:使用正則指定
FilterType.CUSTOM:使用自定義規則,自已寫類,實現TypeFilter接口>

2、scope 定義掃描規則

scope 主要作用是定義Bean在IOC容器中的創建規則
prototype: 多實例:IOC容器啓動並不會去調用方法創建對象放在容器中,而是每次獲取的時候纔會調用方法創建對象
singleton: 單實例(默認),IOC容器啓動會調用方法創建對象放到IOC容器中以後每交獲取就是直接從容器(理解成從map.get對象)中拿
request: 主要針對WEB應用,同一次請求創建一個實例
session: 同一個session創建一個實例

@Configuration
public class Cap02MainConfig {
    @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Bean
    public Person person(){
        System.out.println("創建了一個person對象");
        return new Person();
    }
}

@Test
public void testScope(){
    ApplicationContext app = new AnnotationConfigApplicationContext(Cap02MainConfig.class);
    System.out.println("IOC容器初始化完成了");
    Person person1 = app.getBean("person", Person.class);
    
    Person person2 = app.getBean("person", Person.class);
    System.out.println("person1 == person2 is "+(person2 == person1));
}

打印結果:
如果不加,@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

創建了一個person對象
IOC容器初始化完成了
person1 == person2 is true

加@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)

IOC容器初始化完成了
創建了一個person對象
創建了一個person對象
person1 == person2 is false

得出結論默認情況在AnnotationConfigApplicationContext創建的時候,Spring自動就完成了所有相關bean的創建,並且是單例類;如果加入Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 是多實例類,並且不是隨着ApplicationContext的創建而創建。

3、lazy懶加載

@Configuration
public class Cap02MainConfig {
    //@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
    @Lazy
    @Bean
    public Person person(){
        System.out.println("創建了一個person對象");
        return new Person();
    }
}

@Test
public void testScope(){
    ApplicationContext app = new AnnotationConfigApplicationContext(Cap02MainConfig.class);
    System.out.println("IOC容器初始化完成了");
    Person person1 = app.getBean("person", Person.class);
    
    Person person2 = app.getBean("person", Person.class);
    System.out.println("person1 == person2 is "+(person2 == person1));
}

打印結果:

IOC容器初始化完成了
創建了一個person對象
person1 == person2 is true
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章