Spring注解-(二)@Bean的多种用法详解

本文最后更新于:June 13, 2022 am

Spring 是目前主流的 Java Web 开发框架,是 Java 世界最为成功的框架。Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。该框架是一个轻量级的开源框架,具有很高的凝聚力和吸引力。Spring 框架不局限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何 Java 应用都可以从 Spring 中受益。Spring 框架还是一个超级粘合平台,除了自己提供功能外,还提供粘合其他技术和框架的能力。

目录

autowire属性

已经被启用。加上了此属性后,在使用对应Bean的时候就无需再使用注解@Autowire进行注入,而是自动进行注入。

1
2
3
4
@Bean(autowire = Autowire.BY_NAME)
public OrderS orderS(){
return new OrderS();
}

再使用时,只需要直接使用即可:

1
private OrderS orderS;

而不使用此属性原本的用法:

1
2
@Autowired
private OrderS orderS;

📢注意:此属性已经被弃用!!!

autowireCandidate属性

默认值为true,自动装备的候选者。现在先来看一个示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.SpringTestAnnotation;

import com.SpringTestAnnotation.TestValue.OrderS;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.PropertySource;

/**
* @Author DragonOne
* @Date 2022/6/10 11:16
* @墨水记忆 www.tothefor.com
*/
@ComponentScan("com.SpringTestAnnotation")
@PropertySource("classpath:application.properties")
public class TestConfig {

@Bean
public OrderS orderS(){
return new OrderS();
}

@Bean
public OrderS orderS1(){
return new OrderS();
}

}

现在这里同时注册了两个相同类型的Bean,然后我们再使用注解进行自动注入:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.SpringTestAnnotation.TestValue;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

/**
* @Author DragonOne
* @Date 2022/6/10 11:16
* @墨水记忆 www.tothefor.com
*/
@Component("per")
public class Per {

@Autowired
private OrderS orderS111;

public void show(){
System.out.println("Per show "+orderS111);
}

}

然后再测试:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
package com.SpringTestAnnotation;

import com.SpringTestAnnotation.TestValue.Per;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

/**
* @Author DragonOne
* @Date 2022/6/10 11:16
* @墨水记忆 www.tothefor.com
*/
public class TestAnnotation {
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(TestConfig.class);
Per per = applicationContext.getBean("per", Per.class);
per.show();
}
}

当跑了上面的代码后,我们会发现报错了。我们可以看一下报错的信息:

1
警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'per': Unsatisfied dependency expressed through field 'orderS111'; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.SpringTestAnnotation.TestValue.OrderS' available: expected single matching bean but found 2: orderS,orderS1

大致意思就是说,现在通过类型找到了两个,然后再根据属性的名称orderS111再去找,但是发现找到的两个中并没有名称为orderS111的,所以也就是没有找到。

如果业务又需要上面TestConfig中的两个方法,现在怎么解决呢?

那么就需要对某一个方法的@Bean中加入一个属性:autowireCandidate,并对其赋值为false,因为默认为true。它表示:能不能进行依赖注入的一个候选者。即表示这个Bean不能注入给其他Bean,也就是不能进行依赖注入。(个人简单理解:被标记为false后就表示不能进行注入了,也就相当于这个Bean没有一样)

自定义注解

@Bean除了上面的使用方法外,也可以写在某一个自定义注解上面。例如,原本需要使用以下方式注入一个Bean:

1
2
3
4
5
@Bean
@Scope("prototype")
public OrderS orderS(){
return new OrderS();
}

但是,如果有很多Bean都是这样写的,而且在后续中还有可能会发生改变,那么这种写法肯定是比较麻烦的。所以,可以通过自定义注解的方式完成这个任务,就和@Value中的自定义注解一样。

自定义注解:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
package com.SpringTestAnnotation.TestValue;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
* @Author DragonOne
* @Date 2022/6/12 08:08
* @墨水记忆 www.tothefor.com
*/

@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Bean
@Scope("prototype")
public @interface OurAnno {
}

然后使用:

1
2
3
4
@OurAnno
public OrderS orderS(){
return new OrderS();
}

这样以来,如果我们需要修改@Scope的值,那么只需要在自定义注解中进行修改即可,实现动一发而牵动全局。