关于spring boot中几种注入方法的一些个人看法
前言
最近在知乎上面看到一篇关于程序员面试的问题,面试官问我们一般有几种注入的方法,这几种注入的方法分别在什么时候运用比合理,当时我看到这个时候懵逼了,由于我自己也是刚刚接触springboot不久,所以就自己在平时运用的上面总结了一些知识点常用的几种springboot的注入方法,由于我是一个小萌新,所只要是能够起道注入的方法的注解我都列出来,有可能会有错,希望大家能够及时提出来我来解决:
- @Autowired
- @Resource
- @Component
- @Configuration
- @Qualifie
- @Bean
- ........
这几种常用的吗?难道还有什么其他的?当然有,下面我总结了一下自己对于这几种注入的看法和认识。
首先是我们使用频率较为高的@Autowired:
这个注解可能是我们使用频率较为频繁的一个注解的了,几乎在刚刚入门的时候,我们都会使用这个注释,那么@Autowired注释的工作原理是什么呢?
第一:其实在启动springIoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性
第二:@Autowired注释,它可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作。通过@Autowired的使用来消除set,get方法。在使用@Autowired之前,我们对一个bean配置起属性时,是这用用的
通过这种方式来,配置比较繁琐,而且代码比较多。在Spring2.5引入了@Autowired注释
我们平常直接引用的时候很少注意这些,只是自己写好了一个方法或者springboot自动配置好的一个方法我们要在另一个类中去调用,这个时候,我们就会采用该注释,例如:我已经写好一个工具类,此时,我需要在其他类中调用该工具类的方法:
/*
这是要被调用的类
*/
@Repository("userRepository")
publicclassUserRepositoryImpsimplementsUserRepository{
@Override
publicvoidsave(){
System.out.println("UserRepositoryImpssaveissuccess");
}
}
已调用的类
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.stereotype.Service;
importcom.proc.bean.repository.UserRepository;
/*
方法注入的类
*/
@Service
publicclassUserService{
@Autowired
privateUserRepositoryuserRepository;
publicvoidsave(){
userRepository.save();
}
}
接着我们开始聊一下@Resource这个注解:
第一:@Resource(这个注解属于J2EE的),默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
第二:可以用在方法、属性、类上,通过CommonAnnotationBeanPostProcessor类实现依赖注入与@AutoWired一致。但可以指定name属性来指定beanName,但如果name对应的bean不存在,则会抛出异常,且没有required属性。
当作用在类上面的时候:可以用来指定name
@Resource(name="testMapper") privateTestMappertestMapper;
第三:@Autowired默认按类型装配(这个注解是属业spring的),默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false
@Autowired() privateStudentDaostudentDao;
来,继续往下走,开始撸@Component这个注解:
第一:@Component泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注。
第二:@component(把普通pojo实例化到spring容器中,相当于配置文件中的
例如下面的这个例子
注意:这个只能作用于类上面
packagecn.com.scitc.security;
importcom.fasterxml.jackson.databind.ObjectMapper;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springframework.beans.factory.annotation.Autowired;
importorg.springframework.security.core.Authentication;
importorg.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
importorg.springframework.stereotype.Component;
importjavax.servlet.ServletException;
importjavax.servlet.http.HttpServletRequest;
importjavax.servlet.http.HttpServletResponse;
importjava.io.IOException;
importjava.io.PrintWriter;
@Component("myLoginSuccessHandler")
publicclassMyLoginSuccessHandlerextendsSavedRequestAwareAuthenticationSuccessHandler{
privateLoggerlogger=LoggerFactory.getLogger(getClass());
@Autowired
privateObjectMapperobjectMapper;
@Override
publicvoidonAuthenticationSuccess(HttpServletRequestrequest,HttpServletResponseresponse,Authenticationauthentication)throwsServletException,IOException{
response.setContentType("application/json;charset=UTF-8");
logger.info("登录成功");
PrintWriterout=response.getWriter();
out.write(objectMapper.writeValueAsString("登录成功"));
out.flush();
out.close();
}
}
看了这么多,是不是有点累了,不行接着撸@Configuration的注解:
首先我们先明白从Spring3.0,@Configuration用于定义配置类,可替换xml配置文件,被注解的类内部包含有一个或多个被@Bean注解的方法,这些方法将会被AnnotationConfigApplicationContext或AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
在使用的时候需要注意:
1.@Configuration不可以是final类型;
2.@Configuration不可以是匿名类;
3.嵌套的configuration必须是静态类。
下面讲解详细的使用
第一:用@Configuration加载spring
1.1、@Configuration配置spring并启动spring容器
1.2、@Configuration启动容器+@Bean注册Bean
1.3、@Configuration启动容器+@Component注册Bean
1.4、使用AnnotationConfigApplicationContext注册AppContext类的两种方法
1.5、配置Web应用程序(web.xml中配置AnnotationConfigApplicationContext)
第二:组合多个配置类
2.1、在@configuration中引入spring的xml配置文件
2.2、在@configuration中引入其它注解配置
2.3、@configuration嵌套(嵌套的Configuration必须是静态类)
2.4、@EnableXXX注解
2.5、@Profile逻辑组配置
2.6、使用外部变量
下面讲解一个比较常用的例子:不知道各位大佬的在用在SpringBoot中使用Security安全框架的时候会出现一个默认的登录界面,但是我们一般不回去用哪个登录界面,这时候我们就应该自己去写一个登录的界面以及后端的实行方法,那么这个时候,@configuration就派上用场了,话不多说,直接上例子:
packagecn.com.scitc.config;
importorg.springframework.boot.web.server.ConfigurableWebServerFactory;
importorg.springframework.boot.web.server.ErrorPage;
importorg.springframework.boot.web.server.WebServerFactoryCustomizer;
importorg.springframework.context.annotation.Bean;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.http.HttpStatus;
@Configuration
publicclassErrorConfigurar{
/**
*自定义错误页面
*@return
*/
@Bean
publicWebServerFactoryCustomizerwebServerFactoryCustomizer(){
return(factory->{
ErrorPageerrorPage404=newErrorPage(HttpStatus.NOT_FOUND,"/404");
ErrorPageerrorPage500=newErrorPage(HttpStatus.INTERNAL_SERVER_ERROR,"/500");
ErrorPageerrorPage403=newErrorPage(HttpStatus.FORBIDDEN,"/403");
factory.addErrorPages(errorPage404);
factory.addErrorPages(errorPage403);
factory.addErrorPages(errorPage500);
});
}
}
注意:该注释也是用于全局的,所以定义在类上面。
接下来来一个就比较简单的@Qualifier了,这个注解在我认为就是@Autowired的小弟,它一般和@Autowired一起用,当@Autowired()不带参数的时候@Qualifie就可以带上参数。Qualifier限定描述符除了能根据名字进行注入,更能进行更细粒度的控制如何选择候选者。
@Autowired() @Qualifie("/studentDao") privateStudentDaostudentDao;
现在继续撸一个叫@Bean的注解;
很多人就会问@Bean为什么可以当做注入来用呢?在刚刚开始的时候我也是认为@Bean就是封装一个POJO类而已,可是后面我觉得它是可以用来当做注入注解来使用的。
首先,@Bean可理解为用spring的时候xml里面的
其次,@Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里,添加的bean的id为方法名;
@Configuration
publicclassAppConfig{
@Bean
publicTransferServicetransferService(){
returnnewTransferServiceImpl();
}
}
再接着:@bean也可以依赖其他任意数量的bean,如果TransferService依赖AccountRepository,我们可以通过方法参数实现这个依赖;
@Bean
publicTransferServicetransferService(AccountRepositoryaccountRepository){
returnnewTransferServiceImpl(accountRepository);
}
最后讲一下,指定bean的scope
使用@Scope注解来指定使用@Bean定义的bean
@Scope("prototype")
设置@Scope的属性proxyMode来指定,默认是ScopedProxyMode.NO,你可以指定为默认是ScopedProxyMode.INTERFACES或者默认是ScopedProxyMode.TARGET_CLASS。
@Bean
@SessionScope
publicStuPreferencesstuPreferences(){
returnnewStuPreferences();
}
@Bean
publicServiceStuService(){
StuServiceservice=newSimpleStuService();
service.setStuPreferences(StuPreferences());
returnservice;
}
通过上面的说明,就足以说明这是可以用来注入的。
最后,我们来探讨一下privatefinal修饰的变量可以被用来作为注入你们觉得可以吗?
试想,在一个大的项目中,几乎所有的引用都是用public、@Bean等相应的方法注入,那么就会造成代码的耦合度较高,造成了项目的维护困难,那么久只有被项目经理K一顿啦。