Spring实现类注入注意点

1.Spring常用标签

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration把一个类作为一个IoC容器,它的某个方法头上如果注册了@Bean,就会作为这个Spring容器中的Bean。
@Scope注解 作用域
@Lazy(true) 表示延迟初始化
@Service用于标注业务层组件、
@Controller用于标注控制层组件(如struts中的action)
@Repository用于标注数据访问组件,即DAO组件。
@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
@Scope用于指定scope作用域的(用在类上)
@PostConstruct用于指定初始化方法(用在方法上)
@PreDestory用于指定销毁方法(用在方法上)
@Resource 默认按名称装配,当找不到与名称匹配的bean才会按类型装配。
@DependsOn:定义Bean初始化及销毁时的顺序
@Primary:自动装配时当出现多个Bean候选者时,被注解为@Primary的Bean将作为首选者,否则将抛出异常
@Autowired 默认按类型装配,如果我们想使用按名称装配,可以结合@Qualifier注解一起使用
@Autowired @Qualifier(“personDaoBean”) 存在多个实例配合使用

   当一个接口有两个不同的实现方法时,Spring在注入的时候会由于不知道该注入那个一个实现而报错。可以通过@Primary告诉spring在犹豫的时候优先选择哪一个具体的实现。
场景:
   定义接口:

1
2
3
public interface Singer {
String sing(String lyrics);
}

   有下面的两个实现类:

1
2
3
4
5
6
7
8
@Component // 加注解,让spring识别
public class MetalSinger implements Singer{

@Override
public String sing(String lyrics) {
return "I am singing with DIO voice: "+lyrics;
}
}

   注意,这里没有注解

1
2
3
4
5
6
public class OperaSinger implements Singer {
@Override
public String sing(String lyrics) {
return "I am singing in Bocelli voice: "+lyrics;
}
}
1
2
@Autowired
private Singer singer;

   在注入Singer对象时,会报错误:I am singing with DIO voice: song lyrics. 原因很简单,就是OperaSinger这个类上面根本没有加上注解@Copmonent或者@Service,所以spring注入的时候,只能找到MetalSinger这个实现类.所以才有这个结果。

   但是如果一旦 OperaSinger 这个类加上了@Copmonent 或者 @Service 注解,有趣的事情就会发生,你会发现一个错误的结果或异常:

1
org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [main.service.Singer] is defined: expected single matching bean but found 2: metalSinger,operaSinger

   第一种解决办法:提示很明确了,spring 根据类型无法选择到底注入哪一个。这个时候@Primay 可以闪亮登场了。

1
2
3
4
5
6
7
8
9
@Primary
@Component
public class OperaSinger implements Singer{

@Override
public String sing(String lyrics) {
return "I am singing in Bocelli voice: "+lyrics;
}
}

   如果代码改成这样,再次运行,结果如下:I am singing in Bocelli voice: song lyrics, 用@Primary 告诉spring在犹豫的时候优先选择哪一个具体的实现。
   第二种解决办法:用@Qualifier这个注解来解决问题,将上面的两个类改为如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Component // 加注解,让spring识别
@Qualifier("metalSinger")
public class MetalSinger implements Singer{

@Override
public String sing(String lyrics) {
return "I am singing with DIO voice: "+lyrics;
}
}

@Component
@Qualifier("opreaSinger")
public class OperaSinger implements Singer {
@Override
public String sing(String lyrics) {
return "I am singing in Bocelli voice: "+lyrics;
}
}

   然后在调用的方法上面使用@Qualifier标签,@Qualifier限定哪个bean应该被自动注入。当Spring无法判断出哪个bean应该被注入时,@Qualifier注解有助于消除歧义bean的自动注入。

1
2
3
4
5
6
7
8
9
10
11
12
@Component
public class SingerService {
private static final Logger logger = LoggerFactory.getLogger(SingerService.class);

@Autowired
private Singer singer;

@Qualifier("opreaSinger")
public String sing(){
return singer.sing("song lyrics");
}
}

2.Spring自定义Bean

   springboot的标签生成bean方式,bean的名称是与方法名称相匹配的:

1
2
3
4
5
@Bean
@ConditionalOnBean(WxConfig.class)
public WxAuthService wxBindService(WxService wxService) {
return new WxAuthServiceAdapter(wxService);
}

   上面的bean的名称为wxBindService.也可在@Bean(””)指定生成bean的名称,比如:@Bean("wxAuthService")

注意点:
   ① @Bean用在方法上,@Component用在类上,用了这2个注解就可以将自定的bean就放入ioc了。注意:有@Bean的方法的类,必须加上@Configuration,表明这个是个配置类,相当于xml文件的作用。不然,你加上@Bean没有用啊!!
   ② @ConfigurationProperties作用是绑定配置文件中的值和类的成员变量,使得new出的对象是有初始值的。但是,用了这个注解后,类并没有到容器中。必须要加@Component,放入容器。

1
2
3
4
5
6
7
8
9
10
11
12
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "casic.filestore.minio")
public class MinioProperties {
private String url;
private String accessKey;
private String secretKey;

public MinioProperties() {

}
//设置set、get方法

   通过@ConfigurationProperties标签,在创建MinioProperties对象的时候,会自动设置MinioProperties对象中的字段的初始值为配置文件中设置的值。
   ③ 如果不用Component,那么需要注入上面这个对象的类,必须加上@EnableConfigurationProperties。这样,使用了@EnableConfigurationProperties这个注解后,IOC容器中也会有了。那么你就可以在这个类中使用@AutoWired 等注解来注入上述组件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
import io.minio.MinioClient;
import io.minio.errors.InvalidEndpointException;
import io.minio.errors.InvalidPortException;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;

import javax.crypto.KeyGenerator;
import java.security.NoSuchAlgorithmException;

@Configuration
@EnableConfigurationProperties(MinioProperties.class)
public class FileStoreConfig {

@Bean
@Lazy
public MinioClient minioClient(MinioProperties minioProperties) throws InvalidPortException, InvalidEndpointException {
MinioClient minioClient = new MinioClient(minioProperties.getUrl(),minioProperties.getAccessKey(),minioProperties.getSecretKey());
return minioClient;
}
}

3.开发常见标签

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
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
@ApiImplicitParams:用在请求的方法上,表示一组参数说明
@ApiImplicitParam:用在@ApiImplicitParams注解中,指定一个请求参数的各个方面
name:参数名
value:参数的汉字说明、解释
required:参数是否必须传
paramType:参数放在哪个地方
· header --> 请求参数的获取:@RequestHeader
· query --> 请求参数的获取:@RequestParam
· path(用于restful接口)--> 请求参数的获取:@PathVariable
· body(不常用)
· form(不常用)
dataType:参数类型,默认String,其它值dataType="Integer"
defaultValue:参数的默认值

@ApiResponses:用在请求的方法上,表示一组响应
@ApiResponse:用在@ApiResponses中,一般用于表达一个错误的响应信息
code:数字,例如400
message:信息,例如"请求参数没填好"
response:抛出异常的类

@Validated:用于校验请求中的数据是否正常。即修饰实体类时,通过在实体类中的字段上添加类似
@NotNull@Size(max=32,message="code is null")
等标签,如果在请求时数据异常则会统一抛出异常,方便异常中心统一处理。
@PathVariable:带占位符的 URL 是 Spring3.0 新增的功能;
通过 @PathVariable 可以将 URL 中占位符参数绑定到控制器处理方法的入参中:
URL 中的 {xxx} 占位符可以通过@PathVariable(“xxx“) 绑定到操作方法的入参中;
@TableLogic:在字段上加上这个注解再执行BaseMapper的删除方法时,删除方法会变成修改
@TableField@TableField(exist = false)注解加载bean属性上,表示当前属性不是数据库的字段,但在项目中必须使用,
这样在新增等使用bean的时候,mybatis-plus就会忽略这个,不会报错
@NotBlank(message = "密码不能为空!")
设置字段的验证规则,不需要再业务层再进行单独判断

@TableLogic:注解表示逻辑删除,在字段上加上这个注解再执行BaseMapper的删除方法时,删除方法会变成修改
没有@TableLogic注解调用deleteById/removeById,直接删除数据。
SQL:delete from table where id = 1
有注解走Update方法
SQL:Update table set isDelete = 1 where id = 1

Swagger:
@JsonIgnore:不让前端或文档显示某字段注解

Lombok:
@EqualsAndHashCode(callSuper = true):
a.这个注解会生成equals(Object other) 和 hashCode()方法。 
b.它默认使用非静态,非瞬态的属性 
c.可通过参数exclude排除一些属性 
d.可通过参数of指定仅使用哪些属性 
e.它默认仅使用该类中定义的属性且不调用父类的方法 
f.可通过callSuper=true解决e问题。让其生成的方法中可以调用父类的方法。