Spring的使用核心
sprng就是一个容器,容器最重要的作用就是存放东西的的,而Spring就是一个存放类的容器,将类存进来并进行管理。因此在使用好Spring就需要关注两个重点,那就是如何将类放入到容器中,需要的时候如何取出来。
存对象(注册)
一:类注解
在类上使用注解 @Controller , @Service , @Repository , @Component 。需要保证该类会被Spring扫描到,这种定义方式默认会注册一个名称为类名首字母小写的Bean对象到容器中。
一、四个类注解的含义以及业务流程:
二、@Bean
当前类被 Spring 扫描到时,可以在方法上使用 @Bean 注解,通过方法返回类型,也可以定义、注册Bean对象,默认使用方法名作为Bean的名称。
@Bean
public User user1(){
User user = new User();
user.setUsername("abc");
user.setPassword("123");
return user; }
@Bean
public User user2(){
User user = new User();
user.setUsername("我不是汤神");
user.setPassword("tang");
return user; }
三、@Configuration
在类被Spring扫描到时,使用 @Configuration 注解,可以注册一个配置类到容器中。配置类一般用来自定义配置某些资源。
@Configuration
public class AppConfig {
}
lombok插件:
lombok 通过自定义的类注解,将自定义的类注解在程序编译的时候,转换成相应的JVM可以运行的代码来实现的。主要提供了@Getter、@Setter、@ToString、@Data等注解。@Getter对类里面的所有属性读取,给每一个属性生成一个原生的Get方法。’@Setter、@ToString类似。@Data注解包含了其他注解的功能,包括获得get,set等方法。
取对象
一、通过类型获取:
这种获取方式要求该类型的Bean只能有一个实例,当有两个实例的时候,通过类名.class得到的都是同一个类,并不能知道想要获得哪一个实例。所以只能有一个实例
//方法一、通过类型来获取
LoginController loginController =
context.getBean(LoginController.class);
System.out.println("方法一" + loginController);
二、通过名称获取:
同一个类型的Bean可以有多个,需要注意的是,getBean里的字符串。当类名的第一个字母是大写第二个字母是小写的时候,需要将这个大写的字母变小写。当前两个字母都是大写的时候不需要变小写。
//方法二、通过类名来获取,获取到的是object对象,所以这里需要强转
LoginController loginController =
(LoginController)context.getBean("loginController") ;
//loginController是类名的第一个字母小写得来的,有固定写法,与下面的方法三不一样
System.out.println("方法二" + loginController);
三、通过类型字符串(实例的名字)加类型
//方法二、通过类名来获取,获取到的是object对象,所以这里需要强转
LoginController loginController =
(LoginController)context.getBean("loginController1",LoginController.class) ;
//loginController1是LoginController类的一个实例对象的名字
System.out.println("方法三" + loginController);
依赖注入
注入是从Spring 中取出某个对象,然后将这个取出来的对象赋值给具体类的属性引用,一般有属性注入,setter方法注入,属性注入。用@Autowired注解。
注册和注入的区别
注册是将这个类添加到容器中,让容器具有这个类(类的对象)。就比如我们上学时,班级的花名册一样,每个同学都应该将自己的姓名等信息进行登记,这样班级才会知道有哪些学生。有的时候,一个类的属性时类一个类的实例对象,而注入就是将容器里的类的实例取出来,赋值给该类的属性即可,这样我们就能直接用了。(实例化是容器中的,我们不用再进行new了,Spring帮我们创建了)。
属性注入:
当前类被 Spring 扫描到时,可以在属性上使用 @Autowired 注解,会将容器中的Bean对象装配进来
@Autowired
private LoginRepository loginRepository;
在setter方法上使用 @Autowired 注解进行注入
private LoginService loginService ;
@Autowired
public void setLoginService(LoginService ls) {
this.loginService = ls;
}
其实只要写在方法上的 @Autowired 注解,都会将容器中的Bean对象注入方法参数,setter注入本质也是这样,只是setter方法一般都是设置属性用的,所以也归到属性注入。
构造方法注入:
当前类被 Spring 扫描到时,可以在构造方法上使用 @Autowired 注解,作用也是和setter方法类似,会将容器中的Bean对象注入方法参数。
@Service
public class LoginServiceByConstructor {
private LoginRepository loginRepository;
@Autowired
public LoginServiceByConstructor(LoginRepository loginRepository){
System.out.printf("LoginServiceByConstructor: %s%n",
loginRepository);
this.loginRepository = loginRepository;
}
}
注入指定的Bean:@Qualifier
同类型的Bean有多个时,注入该类型Bean需要指定Bean的名称:
- 属性名或方法参数名设置为Bean的名称
- 属性名或方法参数设置 @Qualifier(“名称”) 注解,注解内的字符串是Bean对象的名称
以下 loginController 中定义了2个用户对象,且在方法参数中注入了Bean对象:
@Controller
public class LoginController {
@Autowired
private LoginService loginService;
@Autowired
@Qualifier("user1")
private User u;
@Autowired
private User user2;
@Bean
public User user1(){
User user = new User();
user.setUsername("abc");
user.setPassword("123");
return user;
}
@Bean
public User user2(){
User user = new User();
user.setUsername("张三");
user.setPassword("tang");
return user;
}
Bean的作用域
Spring 容器在初始化一个 Bean 的实例时,同时会指定该实例的作用域。Spring有6个作用域,最后四种是基于Spring WebMVC生效:
//设置作用域
@Scope("singleton")
@Scope("prototype")
singleton
Spring IoC 容器中只会存在一个共享的 Bean 实例,无论有多少个Bean 引用它,始终指向同一对象。该模式在多线程下是不安全的(单例模式)。Singleton 作用域是Spring 中的缺省作用域(默认),也可以显示的将 Bean 定义为 singleton 模式,配置为:
通常无状态的Bean使用该作用域。无状态表示Bean对象的属性状态不需要更新。Spring默认选择该作用域
prototype
每次对该作用域下的Bean的请求都会创建新的实例。每个 Bean 实例都有自己的属性和状态,而 singleton 全局只有一个对象。根据经验,对有状态的bean使用prototype作用域,而对无状态的bean使用singleton。获取Bean(即通过applicationContext.getBean等方法获取)及装配Bean(即通过@Autowired注入)都是新的对象实例。
request
在一次 Http 请求中,容器会返回该 Bean 的同一实例。而对不同的 Http 请求则会产生新的 Bean,而且该 bean 仅在当前 Http Request 内有效,当前 Http 请求结束,该 bean实例也将会被销毁。
每次http请求会创建新的Bean实例,类似于prototype、一次http的请求和响应的共享、限定SpringMVC中使用
session
在一次 Http Session 中,容器会返回该 Bean 的同一实例。而对不同的 Session 请求则会创建新的实例,该 bean 实例仅在当前 Session 内有效。同 Http 请求相同,每一次session 请求创建新的实例,而不同的实例之间不共享属性,且实例仅在自己的 session请求内有效,请求结束,则实例将被销毁。
在一个http session中,定义一个Bean实例、用户回话的共享Bean, 比如:记录一个用户的登陆信息、限定SpringMVC中使用
application
在一个http servlet Context中,定义一个Bean实例Web应用的上下文信息,比如:记录一个应用的共享信息限定SpringMVC中使用
websocket
在一个HTTP WebSocket的生命周期中,定义一个Bean实例场景:WebSocket的每次会话中,保存了一个Map结构的头信息,将用来包裹客户端消息头。第一次初始化后,直到WebSocket结束都是同一个Bean。限定Spring WebSocket中使用。
Bean的生命周期
对于Bean的生命周期,主要步骤为:
- 实例化Bean:通过反射调用构造方法实例化对象。(将二进制流转化为类对象,由JVM完成)
- 依赖注入:装配Bean的属性,也就是设置属性
- 实现了Aware接口的Bean,执行接口方法:如顺序执行BeanNameAware、BeanFactoryAware、ApplicationContextAware的接口方法。
- Bean对象初始化前,循环调用实现了BeanPostProcessor接口的预初始化方法
(postProcessBeforeInitialization) - Bean对象初始化:顺序执行@PostConstruct注解方法、InitializingBean接口方法、init-method方法(此时执行权属于程序,开始执行业务代码)
- Bean对象初始化后,循环调用实现了BeanPostProcessor接口的后初始化方法
(postProcessAfterInitialization) - 容器关闭时,执行Bean对象的销毁方法,顺序是:@PreDestroy注解方法、DisposableBean接口方法、destroy-method
补充说明:第一步的实例化是指new对象,Spring的语义中说初始化Bean包含Bean生命周期中的初始化步骤。
以下为核心步骤