首頁 > 軟體

SpringBoot Bean花式註解方法範例下篇

2023-02-12 06:01:31

1.容器初始化完成後注入bean

import lombok.Data;
import org.springframework.stereotype.Component;
@Component("miao")
@Data
public class Cat {
}

被注入的JavaBean

import org.springframework.context.annotation.Configuration;
@Configuration
public class Config5 {
}

被載入的設定類

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.Cat;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        context.registerBean(Cat.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

在載入設定類的時候,普通的ApplicationContext不具備該功能。

可以看到其還具有掃描JavaBean註解的功能,直接把名字裝配了,沒有自定義名字的話就是類名首字母小寫。

那麼同一個實體類被載入多次會怎麼樣呢?

import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
@Component("miao")
@Data
@NoArgsConstructor
public class Cat {
    String shout;
    public Cat(String shout) {
        this.shout = shout;
    }
}
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config5 {
}
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.Cat;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        context.registerBean(Cat.class,"1");
        context.registerBean(Cat.class,"2");
        context.registerBean(Cat.class,"3");
        Cat miao = context.getBean("miao",Cat.class);
        System.out.println(miao.getShout());
    }
}

可以看到如果被載入多次的話,後面會覆蓋前面的。

這個和我們在設定yml檔案屬性時有異曲同工之妙,設定了就是你的設定,沒有設定就是預設的,你的設定會覆蓋預設的設定,其中那些設定背後就是一個一個的bean物件罷了。

2.匯入源的程式設計式處理

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
@Component("miao")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
    String shout;
}
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"yi.beans.Cat"};
    }
}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import yi.beans.MyImportSelector;
@Configuration
@Import(MyImportSelector.class)
public class Config5 {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

可以看到註冊了bean,並且還識別到了註解的value值。

不過這種方式還僅不於此,還可以做很多判定。

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        boolean b = annotationMetadata.hasAnnotation("org.springframework.context.annotation.Configuration");
        if (b){     //判斷是否包含這個註解
            return new String[]{"yi.beans.Cat"};
        }else {
            return new String[]{"yi.beans.Dog"};
        }
    }
}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import yi.beans.MyImportSelector;
//@Configuration
@Import(MyImportSelector.class)
public class Config5 {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.Cat;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

可以看到,我們通過API可以達到多種多樣的效果,不僅有檢視註解是否存在啊,還能獲取註解的所有引數等等。

@Configuration註解如果不被@ComponentScan掃描的話,直接被容器載入。是可以省略的,所以後面我是用@Import也是可以的。

3.bean裁定

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
@Component("miao")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
    String shout;
}

實體類我通過註解給它的bean賦了名字。

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(Cat.class).getBeanDefinition();
        registry.registerBeanDefinition("mao",beanDefinition);
    }
}

AnnotationMetadata這個屬性我忽略了,因為這就是上一個定義bean的方式,可以通過後設資料對其條件判斷,你可以結合到一塊。下面是定義了bean的名字,不過還有許多ApI你可以慢慢看有空的時候。

import org.springframework.context.annotation.Import;
import yi.beans.MyImportBeanDefinitionRegistrar;
@Import(MyImportBeanDefinitionRegistrar.class)
public class Config5 {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

可以看到這裡註解的value值被覆蓋了,在之前的方法中,一直都獲取的是註解的value值為bean的名字,由此說明,這種方式的許可權也開放了不少。

拓展

那麼如果我使用這種方式載入同一個bean載入了多次,是哪個生效呢?我來用介面模擬。可以發現是最後一個被載入的在生效。可能有人會疑問,為什麼bean名字一樣,編譯時不報異常呢?

因為一個專案是分散式的情況下,一個設定bean可能會被多個人修改,需要確保這些bean能夠覆蓋達到重新整理的效果,我猜的,不一定對。

public interface BookService {
    void check();
}
import yi.beans.BookService;
public class BookServiceImpl1 implements BookService {
    @Override
    public void check() {
        System.out.println("書籍是人類進步的階梯");
    }
}
import yi.beans.BookService;
public class BookServiceImpl2 implements BookService {
    @Override
    public void check() {
        System.out.println("書籍是人類進步的階梯");
    }
}
import yi.beans.BookService;
public class BookServiceImpl3 implements BookService {
    @Override
    public void check() {
        System.out.println("書籍是人類進步的階梯");
    }
}
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import yi.beans.impl.BookServiceImpl1;
public class MyImportBeanDefinitionRegistrar1 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl1.class).getBeanDefinition();
        registry.registerBeanDefinition("bookService",beanDefinition);
    }
}
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import yi.beans.impl.BookServiceImpl2;
public class MyImportBeanDefinitionRegistrar2 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl2.class).getBeanDefinition();
        registry.registerBeanDefinition("bookService",beanDefinition);
    }
}
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
import yi.beans.impl.BookServiceImpl3;
public class MyImportBeanDefinitionRegistrar3 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl3.class).getBeanDefinition();
        registry.registerBeanDefinition("bookService",beanDefinition);
    }
}
import org.springframework.context.annotation.Import;
import yi.beans.*;
@Import({MyImportBeanDefinitionRegistrar1.class, MyImportBeanDefinitionRegistrar2.class, MyImportBeanDefinitionRegistrar3.class})
public class Config5 {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.BookService;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        BookService bookService = context.getBean("bookService", BookService.class);
        System.out.println(bookService.getClass());
    }
}

4.最終裁定

基於第七種方式,我們要是就是想要載入某個bean,又不想被其他人的覆蓋該怎麼辦呢?也就是說我們這個類無論載入到哪個位置,都不會被覆蓋。請看第八種方式。

在第七種拓展的基礎上,我們再加如下:

import yi.beans.BookService;
public class BookServiceImpl4 implements BookService {
    @Override
    public void check() {
        System.out.println("書籍是人類進步的階梯");
    }
}

再加一個實現類。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import yi.beans.impl.BookServiceImpl4;
public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl4.class).getBeanDefinition();
        beanDefinitionRegistry.registerBeanDefinition("bookService",beanDefinition);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    }
}

通過BeanDefinition的註冊器實名bean,實現對bean的最終裁定。

import org.springframework.context.annotation.Import;
import yi.beans.*;
@Import({MyImportBeanDefinitionRegistrar1.class, MyImportBeanDefinitionRegistrar2.class, MyPostProcessor.class, MyImportBeanDefinitionRegistrar3.class,})
public class Config5 {
}

可以看到,我將該類沒有放到最後。

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.BookService;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        BookService bookService = context.getBean("bookService", BookService.class);
        System.out.println(bookService.getClass());
    }
}

該類註冊的bean沒有被覆蓋耶。許可權是不是更開放了。bean的載入就到此為止。瞭解這些,springboot的原始碼你讀起來就不會那麼費勁了。

到此這篇關於SpringBoot Bean花式註解方法範例下篇的文章就介紹到這了,更多相關SpringBoot Bean註解方法內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com