gitee网址:https://gitee.com/huadahua/spring-2205.git
Spring-IOC:
- Spring框架2大核心功能:
- IOC:控制反转
将对象的创建权交由Spring去管理,我们需要使用某个对象时,直接从Spring框架获取即可使用。之前创建对象的步骤: class A{} class Test{ main: A a = new A(); //由我们自己创建的 } Spring框架中对象的创建: 对象不需要由我们创建,Spring框架已经帮我们创建好了所有的对象,使用时直接从Spring框架获取对象使用即可。 class B{} class Test{ main: //不能这样做 //new B(); //正确的做法: 从Spring容器中获取B对象 }
- IOC:控制反转
定义Spring Bean
- 定义类,并将类交由Spring去管理,如何实现?
- 显式配置Bean
使用2个注解配合使用,具体做法是: 1. 在项目定义配置类 -- 通过注解@Configuration类定义配置类 @Configuration作用于类上方,则表明这个类是一个配置类 2. 在配置类中定义Bean -- 告诉Spring容器需要去创建哪些Bean对象 判断Spring容器是否已经定义Bean对象的方式:从Spring容器获取该Bean对象 案例步骤: 1. 创建SpringBoot项目 2. 创建包:config用于放配置类 dao包用于保存一些定义的类 3. 创建类:在config包下创建配置类,类名自定义 在dao包下创建UserDao类 4. 配置Bean 在配置类上方添加注解@Configuration 在配置类中定义一个方法用于返回UserDao实例,在该方法上方添加注解@Bean 5. 测试Spring是否已经配置好了Bean对象 获取ApplicationContext对象,然后调用getBean方法获取UserDao实例,如果获取成功,表明Spring配置UserDaoBean成功
- 注意点:通过@Bean显式配置Bean对象,方法名即为Bean对象的id/name,通常我们叫做beanId,beanId是用于检索Bean对象的
- 通过@Bean装配Bean时,若需要注入其他Bean对象,可以使用参数注入Bean对象
@Bean public PersonService personService(PersonDao personDao){ return new PersonServiceImpl(personDao); }
- 隐式配置Bean
1. 通过在类上方添加组件类注解来表明某个类是组件,交由Spring去管理 组件:Spring中定义的类,通过在类上方添加注解来表明是组件 2. 在配置类上方添加注解@ComponentScan("指定包名"),通知Spring去哪里扫描添加了组件类注解的类并装配成Bean对象 组件类注解: @Component 通用组件注解 @Controller / @RestController 控制器组件 @Service 业务层组件 @Repository 持久化/数据层组件 @Configuration 表示配置类组件
- 隐式配置的BeanId,默认情况下为:
1. 若类名是首字母大写,第二个字母小写,则beanId为类名首字母小写: eg:class DogDaoImpl... 对应的BeanId为:dogDaoImpl 2. 否则,beanId和类名保持一致。 eg:class DOgDaoImpl... 对应的BeanId为:DOgDaoImpl
- 隐式配置的BeanId也可以通过在注解@Component(“beanid”)指定BeanId
- 关于显式配置和隐式配置的选择:
在定义自己写的类时,建议使用隐式配置 若想将不是自己写的类装配成Bean时,建议使用显式配置 在一个项目中可以混合使用。
- 隐式配置的BeanId,默认情况下为:
- 显式配置Bean
Spring中所有Bean的实例化时机
Spring框架中,所有的Bean对象都是在Spring程序启动时实例化好的。
因为以上操作,造成的现象:启动Spring程序,启动时间会长一些
问题:为什么Spring不采用懒加载机制?(即什么时候用某个Bean,再创建某个Bean对象)
如果在程序启动时实例化所有的Bean,这种方式程序启动时间会长,但是后续使用Bean时无需再创建Bean,所以使用过程中程序的效率很高
如果采用懒加载方式,即程序启动时不实例化Bean,而是什么时候用,什么时候再实例化,这种方式会降低程序的使用效率。
从Spring容器中获取Bean对象
- ApplicationContext – 应用程序上下文对象
该对象代表Spring容器,会存在于整个项目生命周期中。 所以可以通过该对象获取Spring容器中的所有Bean对象
- 如何获取到ApplicationContext 对象
ApplicationContext context = SpringApplication.run(MyConfig.class);
- 如何通过ApplicationContext对象获取某个Bean对象 – 三种方式
1. 根据数据类型来获取某个Bean对象 UserDao dao = context.getBean(UserDao.class); 注意点:这种获取方式要求:该类型的Bean对象只有一个 2. 根据BeanId来获取Bean对象 StudentDao studentDao = (StudentDao) context.getBean("studentDao"); 注意点:通过beanId获取到的Bean对象类型为Obj ect,需要强转 3. 根据BeanId来获取Bean对象,可以指定数据类型,无需强转 UserDao userDao = context.getBean("userDao",UserDao.class);
Bean的作用域
- 作用域是Bean的属性,可以单独对某个Bean的作用域进行修改
- Spring容器配置Bean对象的时候,默认所有的Bean对象都是单例的。
- Spring容器中Bean的常见作用域:
singleton -- 单例 Spring容器默认的 prototype -- 原型 Spring容器中,每次获取Bean对象,都会重新实例化 request -- 每个request对象代表一次请求,每发起一次请求,都会重新实例化用到的Bean对象 session -- 每次创建一个新的session对象,都会重新实例化用到的Bean对象
- 如何修改作用域:
- 通过注解@Scope来定义,用法为:
@Bean @Scope("prototype") public UserDao userDao(){ return new UserDao(); }
- 通过注解@Scope来定义,用法为:
依赖注入
@AutoWired注入
- 该注解是Spring框架提供的,默认会根据类型进行注入
- 三种注入方式:
1. 构造方法注入 若类中的构造方法只有一个,则@Autowired注解可省略 @Autowired public CatServiceImpl(AnimalDao animalDao){ this.animalDao = animalDao; } 2. set方法注入 @Autowired public void setBearDao(BearDao bearDao){ this.bearDao = bearDao; } 3. 字段注入 @Autowired private CatDao catDao;
- @Autowried可能会产生歧义的问题
案例: interface UserDao{} class UserDaoImpl 实现 UserDao{} class UserDaoImpl1 实现 UserDao{} class UserServiceImpl 实现UserService{ @Autowried private UserDao userDao; }
- @Autowried消除歧义–2种解决办法
- 使用注解@Qualifier
步骤: 定义一个UserDao接口,两个实现类 在UserServiceImpl中通过字段注入UserDao对象,看是否产生歧义 测试@Qualifier注解是否可以解决歧义 注意:可以将三种注入方式全都测试
- @Qualifier注解只能作用于set方法注入和字段注入
- 解决歧义第二种办法:
- @Autowired若产生歧义,此时默认会自动根据beanId去找是否有对应的Bean,若有,则直接注入。
- 使用注解@Qualifier