首頁 > 軟體

關於@Bean的使用方式

2022-08-23 14:02:26

@Bean是一個方法級別上的註解,主要用在@Configuration註解的類裡,也可以用在@Component註解的類裡。

目的是建立一個類。當spring需要建立指定的一個類時會呼叫這個註解(@Bean)的方法。

一個物件

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Info {
    String name;
    int age;
}

就如同在在xml設定中新增一個類的設定。這樣spring在自動建立這個類時會呼叫設定的方法。

<bean id="info" class="zhong.test.springbootdemo.usultestdemo.demo.Info">
    <property name="name" value="sjl"/>
    <property name="age" value="18"/>
</bean>

SprignBoot中 @Bean 完美的替換了了上面的這種在xml中設定的方法。使用以下方法就能讓spring在需要自動建立Info物件時,自動呼叫這個方法。

@Configuration
public class BeanInit {
    /**
     * 測試@Bean的作用
     */
    @Bean(name = "info")
    public Info getInfo(){
        return new Info("gfagduis", 2343);
    }
    @Bean(name = "info1")
    public Info getInfo1(){
        return new Info("gfagdufasfdfdais", 2343);
    }
}

獲取這個類的方法

1、AnnotationConfigApplicationContext 類獲取

@Component
public class BeanTest implements CommandLineRunner {
    private void getBean(){
        ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanInit.class);
        Info info1= ctx.getBean("info",Info.class);
        System.out.println(info1);
    }
    @Override
    public void run(String... args) throws Exception {
        System.out.println(">>>>>>>>>>>>>>>服務啟動執行,執行載入資料等操作<<<<<<<<<<<<<");
        getBean();
    }
}

2、在spring自動建立的類中

在構造方法中設定這個值,這樣spring就會呼叫該類的建立方法來獲取這個初始化的類。

@Component
public class BeanTest implements CommandLineRunner {
    private Info info;
    /**
     *spring建立BeanTest物件時會呼叫這個建構函式。引數是info1,所以會呼叫 @Bean(name = "info1") 註釋的方法
     *
     */
    public BeanTest (Info info1){
        this.info = info1;
    }
    
   private void getBean2(){
        System.out.println(info);
    }
    @Override
    public void run(String... args) throws Exception {
        System.out.println(">>>>>>>>>>>>>>>服務啟動執行,執行載入資料等操作<<<<<<<<<<<<<");
        getBean2();
    }
}

在建構函式中 BeanTest (Info info1) 引數的名稱是info1.所以就呼叫 @Bean(name = “info1”) 的方法來獲取初始化物件。

結果如下:

                          >>>>>>>>>>>>>>>服務啟動執行,執行載入資料等操作<<<<<<<<<<<<<
                         Info(name=gfagdufasfdfdais, age=2343)

同時也是支援多別名設定的 例如:

    @Bean(name = { "info12", "info3", "info3" })
    public Info getInfo2(){
        return new Info("gfa4361783ais", 2343);
    }

測試一下

@Component
public class BeanTest implements CommandLineRunner {
    private Info info;
    private Info info1;
    private Info info2;
    /**
     *spring建立BeanTest物件時會呼叫這個建構函式。引數是info1,所以會呼叫 @Bean(name = "info1") 註釋的方法
     *
     */
    public BeanTest (Info info1, Info info2, Info info3){
        this.info = info1;
        this.info1 = info2;
        this.info2 = info3;
    }
    
   private void getBean2(){
        System.out.println(info);
        System.out.println(info1);
        System.out.println(info2);
    }
    @Override
    public void run(String... args) throws Exception {
        System.out.println(">>>>>>>>>>>>>>>服務啟動執行,執行載入資料等操作<<<<<<<<<<<<<");
        getBean2();
    }
}

結果如下

>>>>>>>>>>>>>>>服務啟動執行,執行載入資料等操作<<<<<<<<<<<<<
Info(name=gfagdufasfdfdais, age=2343)
Info(name=gfa4361783ais, age=2343)
Info(name=gfa4361783ais, age=2343)

當然也可以使用 Qualifier(“xxx”) 來指定 @Bean(name = “xxx”) 中的xxx就可以呼叫對應的方法。

3、使用 @Autowired 註解獲取變數

如果有多個初始化方法,則會根據變數名稱來獲取。

在初始化類中建立以下多個初始方法

 @Configuration
public class BeanInit {
    /**
     * 測試@Bean的作用
     */
    @Bean/*(initMethod = "init")*/
    public Info getInfo(){
        System.out.println("進入方法");
        Info info = new Info("gfagduis", 2343);
        System.out.println("結束方法");
        return info;
    }
    @Bean(name = "info1")
    public Info getInfo1(){
        return new Info("gfagdufasfdfdais", 2343);
    }
    @Bean(name = { "info2", "info3", "info3" })
    public Info getInfo2(){
        return new Info("gfa4361783ais", 2343);
    }
    @Bean
    public Info info(){
        return new Info("gfsdfadsfad4361783ais", 23143);
    }

然後在測試方法中分別用 @Autowired註釋Info類來獲取對應的物件

@Component
public class BeanTest implements CommandLineRunner {
    //private Info info;
    @Autowired
    private Info getInfo;
    @Autowired
    private Info info1;
    @Autowired
    private Info info3;
    @Autowired
    private Info info;
    /*public BeanTest (Info info){
        this.info = info;
    }*/
    private void getBean(){
        /*ApplicationContext ctx = new AnnotationConfigApplicationContext(BeanInit.class);
        Info person = ctx.getBean("info",Info.class);
        System.out.println(person);*/
        System.out.println(getInfo);
        System.out.println(info1);
        System.out.println(info3);
        System.out.println(info);
    }
    @Override
    public void run(String... args) throws Exception {
        System.out.println(">>>>>>>>>>>>>>>服務啟動執行,執行載入資料等操作<<<<<<<<<<<<<");
        getBean();
    }
}

測試結果如下:

>>>>>>>>>>>>>>>服務啟動執行,執行載入資料等操作<<<<<<<<<<<<<
Info(name=gfagduis, age=2343)
Info(name=gfagdufasfdfdais, age=2343)
Info(name=gfa4361783ais, age=2343)
Info(name=gfsdfadsfad4361783ais, age=23143)

在使用 @Autowired 註解時,也可以與 @Qualifier(“xxx”) 指定使用哪個方法來獲取物件。

@Bean 註解的屬性解析

value 和 name

name 和 value 兩個屬性是相同的含義的, 在程式碼中定義了別名。 為 bean 起一個名字,如果預設沒有寫該屬性,那麼就使用方法的名稱為該 bean 的名稱

autowire

裝配方式 有三個選項

  • Autowire.NO (預設設定)
  • Autowire.BY_NAME
  • Autowire.BY_TYPE

指定 bean 的裝配方式, 根據名稱 和 根據型別 裝配, 一般不設定,採用預設即可。

initMethod

bean 的初始化方法, 直接指定方法名稱即可,不用帶括號。初始方法要在對應的POHO中,也就是Info類中。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Info {
    String name;
    int age;
    private void init(){
        System.out.println("進入方法2");
        name = "fhasjdf";
        age = 12;
    }
}
@Configuration
public class BeanInit {
    /**
     * 測試@Bean的作用
     */
    @Bean(name = "info", initMethod = "init")
    public Info getInfo(){
        System.out.println("進入方法");
        Info info = new Info("gfagduis", 2343);
        System.out.println("結束方法");
        return info;
    }

最終結果、:

進入方法
結束方法
進入方法2
2019-09-24 14:57:11.917  INFO 11656 --- [           main] o.s.s.concurrent.ThreadPoolTaskExecutor  : Initializing ExecutorService 'applicationTaskExecutor'
2019-09-24 14:57:12.048  INFO 11656 --- [           main] o.s.b.w.embedded.tomcat.TomcatWebServer  : Tomcat started on port(s): 8080 (http) with context path ''
2019-09-24 14:57:12.051  INFO 11656 --- [           main] z.t.s.u.start.UsulTestStartApplication   : Started UsulTestStartApplication in 1.74 seconds (JVM running for 2.246)
>>>>>>>>>>>>>>>服務啟動執行,執行載入資料等操作<<<<<<<<<<<<<
Info(name=fhasjdf, age=12)

所以最終呼叫的是init()方法來建立類。

destroyMethod

bean 的銷燬方法, 在呼叫 IoC 容器的 close() 方法時,會執行到該屬性指定的方法。不過,只是單範例的 bean 才會呼叫該方法,如果是多範例的情況下,不會呼叫該方法。

注意:

由於spring構造的物件都是單例的,所以只要是從spring ioc中獲取的物件都是同一個,他們中的屬性,即便是私有的非靜態屬性。都是公用的。

public class MyDisposableBean implements DisposableBean {
    public Map<String, String> map = new HashMap<>();
    int i = 0;
    private void init(){
        System.out.println("MyDisposableBean自定義初始化方法");
    }
    private void destroyMethod(){
        System.out.println("自定義銷燬方法,MyDisposableBean物件銷燬");
    }
    public void pringt(){
        System.out.println("-------------------------------");
        System.out.println("i=" + i);
        System.out.println("map.size=" + map.size());
        map.entrySet().stream().forEach(item -> System.out.println("map ->   "+ item.getKey() + "---" + item.getValue()));
    }
}
@Configuration
public class BeanConfigurer {
    @Bean(name = "MyDisposableBean", initMethod = "init", destroyMethod = "destroyMethod")
    public MyDisposableBean getMyDisposableBean(){
        System.out.println("MyDisposableBean構造方法");
        return new MyDisposableBean();
    }
}
@Component
public class DisposableBeanTest implements CommandLineRunner {
    @Override
    public void run(String... args) throws Exception {
        MyDisposableBean myDisposableBean = new MyDisposableBean();
        MyDisposableBean myDisposableBean1 = new MyDisposableBean();
        MyDisposableBean myDisposableBean2 = SpringContextUtils.getBean(MyDisposableBean.class);
        myDisposableBean2.pringt();
        myDisposableBean2.map.put("1", "2");
        myDisposableBean2.i = 2;
        MyDisposableBean myDisposableBean3 = SpringContextUtils.getBean(MyDisposableBean.class);
        myDisposableBean3.pringt();
        myDisposableBean1.pringt();
    }
}

測試結果:

MyDisposableBean構造方法
MyDisposableBean自定義初始化方法
-------------------------------
i=0
map.size=0
-------------------------------
i=0
map.size=0
-------------------------------
i=2
map.size=1
map ->   1---2
-------------------------------
i=0
map.size=0

可以看出,如果是我們自己在程式中new的物件(myDisposableBean 和 myDisposableBean1),其私有屬性map和i是不變的。不相互影響。

另外兩從spring ioc中獲取的物件(myDisposableBean2 和 myDisposableBean3 )的map和i兩個屬性,是公用的。其中一個物件修改值,name另外一個物件的屬性也相應的變化

以上為個人經驗,希望能給大家一個參考,也希望大家多多支援it145.com。


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