目录
今天着重讲解IOC IOC: 控制反转 inverse of controller
Spring框架的核心
IOC 和 AOP
今天着重讲解IOC IOC: 控制反转 inverse of controller
在接触SpringIOC之前,我们在创建对象时,是哪里使用哪里创建,需要一个创建一个,将来可能创建很多的对象。例如:
T t = new T(); t.xx //调用属性和方法等
T t1 = new T();
T t2 = new T();
这时的对象创建权在我们自己手里,你什么时候想创建,自己去创建。而用了Spring之后呢,你无需再自己创建对象,而是向Spring去拿,对象均已经由Spring框架帮你创建好了,若要使用,直接 从Spring容器获取对象即可。容器概念————容器是用来保存东西的。那么保存什么东西呢?保存着你整个项目里面,所有类的对象。每一个类的对象都会保存进来。是Spring帮你创建好的。可能说到这里,大家还是一头雾水...我们后续举例说明。
我们首先来看下怎么将类交由Spring来管理。这里可以理解为通知Spring来管理。通知的方式方法如下:
1.显式配置Bean
通过@Bean
注解完成的,但是
@Bean
注解必然是作用于配置类中的
,@Bean
注解是作用于方法上方的,Bean就是Bean对象,Spring中对象就叫做Bean对象。
配置类:是Spring
框架核心的一个类,通过注解
@Configuration
来表示(如果注解没有学习的同学,建议先去了解下Java中关于注解的介绍)
@Configuration
public class ExplicitConfig{
@Bean
public T t(){ return new T(); }
@Bean
public A a(){ return new A(); }
}
//这两个类不再单独书写,下面表示已创建这两个类
class T{}
class A{}
Spring
管理
Bean
的机制:
1. 加载配置文件,配置文件加载完成,得到
Spring
容器,所有的
Bean
实例创建完成。
那么这时我们的T 和 A 这两个类就已经交给Spring去管理了,这里注意@Bean是作用在方法上方的,方法的返回值就是 分别返回一个T 和 A的对象。
Bean对象的获取:我们在Test类中获取上下文对象ApplicationContext,这里上下文对象大家可以理解为,它是维护那些Bean对象的一个高级接口,就是它里面有很多的方法可以供我们去打点调用。
public class ExplicitTest {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(ExplicitConfig.class);
}
1.
显式配置中,
BeanId
取决于方法名,方法名即为
BeanId
/*1. 根据BeanId获取
getBean(String beanId) - Object*/
T t = (T)context.getBean("t")
因为getBean方法返回的是一个Object对象,所以我们要强转为T对象。
2.
/*2. 根据BeanId,并指定类型获取 getBean(String beanId,Class<T>) - T*/
T t = context.getBean("t",T.class)
这里由于指定了类型 所以不再需要强转.
3.
/*3. 根据类型获取 getBean(Class<T>) -- T
注意:根据类型获取必须要求该类型的实例只有一个*/
T t = context.getBean(T.class)
注意
:
根据类型获取必须要求该类型的实例只有一个,也就是只有这一种T类。.class 不懂的同学可以去看映射相关内容。
还有一种参数注入,由于较为复杂不过多演示。
在配置类中显示配置
Bean
的方法中,可以给出指定类型的参数,
Spring
在调用添加了
@Bean
注解的方式时,会自动根据参数类型找到匹配的
Bean
对象,并将其注入
2.隐式配置Bean
1. 在类的上方添加组件类注解
- @Component
2. 在配置类上方添加注解
@ComponentScan(
指定包
)
,加载配置类时会到指定包下进行组件扫描,例如:
@Configuration
@ComponentScan("com.example.springioc.implicit")
public class ImplicitConfig {
}
同时,我们还要在 期望交给Spring管理的类上方加上组件类的注解,
@Componnent
通用组件注解
@Controller
控制器组件
@Service
业务层组件
@Repository
持久层组件 等等 这些注解没有本质功能的区别,但是由于见名知意,可以更好的让我们理解这个类所在的是哪个模块对应MVC中的哪些业务。例如:
@Controller("t")
public class TController {
@Autowired
public TMapper tMapper;
隐式配置中的BeanId,默认根据类名得知BeanId
- 类名首字母大写,第二个字母小写,
beanId
为首字母小写的名称
- 否则,
beanId
为类全名
可以自定义beanId
,在注解中添加属性值
如@Component("a")
public class ImplicitTest {
public static void main(String[] args) {
ApplicationContext context = SpringApplication.run(ImplicitConfig.class);
StudentController controller = context.getBean("t",TController.class);
注意事项
@ComponentScan
给定的包越精确越好,范围太大,启动速度慢
显式配置和隐式配置的使用建议
--
建议混合使用
自己写的类
--
隐式配置
第三方的类,向交给
Spring
管理
--
显示配置
3.Bean的作用域
Spring
框架中,所有Bean的作用域默认都是单例的(singleton)
单例:某个类的实例在应用程序只有一个
单例:某个类的实例在应用程序只有一个
作用域:
1. singleton --
单例
2. prototype --
原型 即每次从Spring
容器获取某个
Bean
,每次均返回新的实例
3. session --
每个
session
对象均创建一个新的实例
4. request --
每次请求均创建一个新的实例
那么如何修改Bean的作用域呢?
通过注解
@Scope("....")
来修改,配置
Bean
方式不同,作用的位置不同。
-
显式配置
Bean
@Bean
作用在方法上方配置
用法:
@Bean
@Scope("prototype")
public UserController userController(UserMapper userMapper){
return new UserController(userMapper);
}
-
隐式配置
Bean
@Component
作用在类的上方
@Controller("t")
@Scope(("prototype")
public class TController {
@Autowired
public TMapper tMapper;}
4.依赖注入
@Autowired
注解
Spring
框架提供的注解,默认根据类型注入对象
注入方式有
3
种:
1.
构造方法注入
-
注意
:
若构造方法只有一个,则该注解可选
StudentService studentService;
@Autowired
public PersonController(StudentService studentService){
this.studentService = studentService;
System.out.println("PersonController构造注入。。。。。。");
System.out.println(personService); //查看字段注入是否完成
}
2. setter
注入
/set
方法注入
WorkerService workerService;
@Autowired
public void setWorkerService(WorkerService workerService){
System.out.println(personService); //字段注入的值
this.workerService = workerService;
System.out.println("PersonController通过setter注入。。。。。");
}
3.
字段注入(用的最多!!!)
@Autowired
PersonService personService;
注意事项
1.若注入的依赖项不存在,会发生什么?
Spring
容器启动失败,但是若存在这样的需求(不论依赖项是否存在,均要实例化
Bean
,此
时可以使用属性
required=false
),该属性的作用:仅当依赖项存在,才注入,若不存在,
不注入
2.若注入的类型对应的依赖项有多个,又会发生什么?
若注入的类型对应的依赖项存在多个,此时会产生歧义,启动 Spring容器直接报错
2.若注入的类型对应的依赖项有多个,又会发生什么?
若注入的类型对应的依赖项存在多个,此时会产生歧义,启动 Spring容器直接报错
@Autowired
产生歧义的解决办法:
1.
使用
@Qualififier
指定注入的
beanId
若使用
@Autowired
注入时产生了歧义,若有
@Qualififier
,则根据给定的
beanId
进行注
入;若没有
@Qualififier,
此时会自动根据
beanid
进行查找。