一:Spring IOC 2种形式
注意:两种形式获取的Ioc容器是 独立的
1.xml配置文件形式:applicationContext.xml
存bean:
取bean:
ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml”);
context.getBean();
2.注解形式:带有@Configuration注解的类(配置类)
存Bean:@Configuration+@Bean id即为方法名
取bean
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class) ;
注解形式存Bean还有两种方式:
1.必须有@Configuration注解(配置类)
2.形式区别:
- 三层组件加入IOC容器: 给个各类加注解 、 扫描器识别注解所在包
a.给三层组件 分别加注解(@Controller、@Service、@Repository -> 如果不知道具体是哪层可以统一用:@Component)
b.将注解所在包 纳入ioc扫描器(分两种)(ComponentScan)- xml配置文件扫描器:
com.likun.controller 用逗号分隔,同时也可以是com.likun扫描当前包,以及子包。 - 注解扫描器 在@Configuration注解上操作 @ComponentScan(value="com.likun”)
- xml配置文件扫描器:
- 给扫描器指定规则:本来是当前包和子包全部扫描。
但现在可以指定:
excludeFilters:排除过滤
includeFilters:包含过滤
过滤类型:FilterType(ANNOTATION,ASSIGNABLE_TYPE,CUSTOM)
注意:includeFilters有默认行为,可以通过useDefaultFilters = false禁止
区分:
ANNOTATION:Controller.clss 指的是所有标有@Controller的类
ASSIGNABLE_TYPE:指的是具体的一个类 StudentController.class
CUSTOM自定义:自己定义包含规则
@ComponentScan(value="com.likun”)
@ComponentScan(value="com.likun",excludeFilters = { @ComponentScan.Filter(type= FilterType.ANNOTATION,classes ={Controller.class} )} )
@ComponentScan(value="com.likun",includeFilters = {@ComponentScan.Filter(type= FilterType.CUSTOM,classes ={ MyFilter.class})},useDefaultFilters = false)
- 非三层组件(ex:Student.class 、IntToStringConver.class):
i. @Bean+方法的返回值 ,id默认就是方法名(可以通过@Bean("stu") 修改id值)
ii. import 、FactoryBean(四)
二:bean的作用域
研究是不是单例
- 配置文件的方式:
有个属性是scope,可选为单例或者不单例 singleton| prototype,prototype原型或者叫做多实例 - 注解的方式:加一个注解@Scope("singleton”)
执行时机:(产生bean的时机):
singleton:容器在初始化时,就会创建对象(唯一的一个);以后再getBean时,不再产生新的bean。singleton也支持延迟加载(懒加载):在第一次使用时产生。 @Lazy
prototype:容器在初始化时,不创建对象;只是在每次使用时(每次从容器获取对象时 ,context.getBean(Xxxx)),再创建对象;并且 每次getBean()都会创建一个新的对象。
三:条件注解 Spring Boot
可以让某一个Bean 在某些条件下 加入Ioc容器,其他情况下不加入IoC容器。
a.准备 bean 原始的bean (燃油车,新能源车)
b.增加条件Bean:给每个Bean设置条件 ,必须实现Condition接口,会实现一个方法,叫做matches 返回true则加入。
c.根据条件,加入IoC容器
四:回顾给IoC加入Bean的方法
1.配置文件方式
2.注解方式 :全部在基于@Congiration配置类中设置:
- 三层组件: 扫描器 + 三层注解
- 非三层组件:
① @Bean+返回值
②@import
③FactoryBean(工厂Bean)(spring底层提供)- @import使用:(有多种方式)
①直接编写到@Import中,并且id值 是全类名 ex:@Import({Apple.class,Banana.class})
②自定义ImportSelector接口的实现类,通过selectimports方法实现(方法的返回值 就是要纳入IoC容器的Bean的全类名) 。并且 告知程序 自己编写的实现类: @Import({Orange.class,MyImportSelector.class})。实现的类(MyImportSelector.class)中包含了Apple.class和Banana.class 也可以共用加入Orange.class。 实现类返回值:return new String[]{"com.likun.entity.Apple","com.likun.entity.Banana”}
③编写ImportBeanDefinitionRegistrar接口的实现类,重写方法@Import({Orange.class,MyImportSelector.class,ImportBeanDefinitionRegistrar.class}) - FactoryBean(工厂Bean):
①准备bean。实现类和重写方法
②注册bean。注册到@Bean中,注意:需要通过&区分 获取的对象是哪一个 : 不加&,获取的是最内部真实的Apple和非三层中的(① @Bean+返回值)类似;如果加了&,获取的 是FacotryBean
- @import使用:(有多种方式)
五:Bean的生命周期
创建(new …)、初始化(赋初值 init)、 ....、销毁 (servlet destory)
IoC容器的生命周期:初始化容器、..使用容器、销毁容器。
注意:研究的是bean的生命周期:当单例模式的时候,容器会先自己创建一个对象,所以是先出现对象的无参构造,然后出现init方法,也就是初始化。
IoC容器在初始化时,会自动创建对象(构造方法) ->init ->.....->当容器关闭时 调用destroy…
- 方法一: Student.java 也就是可以被叫做bean的类
适用于:@Bean+返回值方式
init destroy
①xml方式:在bean中的属性中设置 init-method="myInit" destroy-method="myDestroy"
②注解: @Bean(value="stu",initMethod = "myInit",destroyMethod = "myDestroy”)
方法二:注解方式;适用于三层注解(是没有bean的)(功能性注解、MyIntToStringConverter.java:转换器: 功能性的类一般用Component):@Controller、@Service、@Repository、@Component
三层注解(功能性注解【三层、功能性类】)三层组件: 扫描器 + 三层注解(4个)
JAVA规范 :JSR250
1. 将响应组件 加入 @Component注解、
2. 给初始化方法加@PostConstruct、
3. 给销毁方法加@PreDestroy ;
@PostConstruct:相当于方法一的init 注解到init方法上
@PreDestroy:相当于方法一的destroy,注解到destroy方法上,如果要获取@Component注解中的bean,那么该Bean的名字就是@Component(value="xxx")的value值
- 方法三:接口方式:两个接口 接口:适用于三层组件(扫描器+三层注解)
InitializingBean初始化
DisposableBean 销毁
初始化:只需要 实现InitializingBean中的afterPropertiesSet()方法
销毁:实现DisposableBean 中的destroy()方法
问题:要在SPring IOC容器中操作:选择哪种操作方式? 对象:Bean+返回 其他:三层组件,当前种类也是适用于三层组件
小结:如果是注解形式 , 随便写一个方法 ,然后加上相应注解即可;如果是接口形式,必须 实现接口中规定的方法
- 方法四:接口方式:一个接口(给容器中的所有Bean加初始化、销毁)重点是研究所有的bean包括了自己
接口:同样适用于三层组件,在接口中可以对bean进行一些修改
接口名字:BeanPostProcessor:拦截了所有中容器的Bean
六:自动装配 : 多用于三层组件(4个注解+扫描器)
Controller->Service->Dao
- 三层组件@Autowired private StudentDao studentDao ; 在Service中注入Dao 通过@Autowired注入Ioc容器中 根据类型自动注入(默认)(没有调用setXxx()方法)
注意:如果@Autowired在属性(private StudentDao studentDao ;)前标注,则不调用setXxx;如果在方法前标注也就是在setXxx前面标注 ,则调用setXxx,如果是在三层注解的前提下是不能放在方法的参数前
两种:
@Autowired
private Xxx xx;
@Autowired
public void setXxx(xx xx)
{
}
- Bean+返回值:@Autowired 可以放在方法的参数前(也可以省略 不建议使用),也可以放在方法前 (构造方法:特殊,如果只有一个有参构造方法,则构造方法前的@Autowired也可以省略 不建议使用)
public void setXxx(@Autowired xx xx)
{
}
- 之前:@Autowired 根据类型(默认)匹配:三层注入方式/@Bean+返回值
1.如果有多个类型相同的,匹配哪个?
报错。 /加一个默认值 在相同的类型前其中一个加 @primary 然后就默认加载加了@primary的
2.能否根据名字匹配?
可以,结合 @Qualifier("stuDao2")使用。前提是对两个相同类型的实现类分别命名@Repository("stuDao2")
3.如果有0个类型相同,默认报错;可以修改成不注入(null),@Autowired(required=false)
- 自动注入方式一: @Autowired (Spring提供) ,默认根据类型
自动注入方式二:@Resource(JSR250:java规范),默认根据名字 (如果有名字,根据名字匹配;如果没有名字,先根据名字查找,如果没找到,再根据类型查找);也可以通过name或type属性 显示的指定根据名字 或类型找。
自动注入方式三:@Inject(JSR330),额外引入javax.inject.jar,默认根据类型匹配
小结:单独的@Autowired根据类型使用,@Autowired加@Qualifier根据名字使用
七:利用Spring底层组件进行开发 (三层组件)
能够供我们使用的组件,都是Aware的子接口,即XxxxAware
- 以ApplicationContextAware为例:实现步骤
a.实现ApplicationContextAware
b.重写其中的方法,都包含了一个对象。只需要将该对象 赋值到属性中即可
有什么用:例如ApplicationContextAware,可以通过该接口 获取到Ioc容器对象。
执行时间: 如果在main()中new Ioc容器: 先执行ApplicationContextAware实现类中的方法,通过该方法传入IoC容器 供我们自己使用; 然后再将该容器通过new返回给用户
- BeanNameAware:
八:环境切换:@Profile
- 激活方式一:
Dspring.profiles.active=@Profile环境名
-Dspring.profiles.active=myApple
例如:数据库环境:两种就可以来回切换
@Profile
127.0.0.1 scott tiger
@Profile
192.168...
- 激活方式二:
硬编码
坑:错误写法
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class) ;
ConfigurableEnvironment environment = (ConfigurableEnvironment)context.getEnvironment();
environment.setActiveProfiles("myBanana");
其中AnnotationConfigApplicationContext中有一个refresh()操作:会将我们设置的一些参数还原
没激活 |->进行激活 ->刷新 ->没激活
流程调整:
没激活->进行激活 | ->刷新
正确写法:
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext() ;
ConfigurableEnvironment environment = (ConfigurableEnvironment)context.getEnvironment();
environment.setActiveProfiles("myApple");
//保存点
context.register(MyConfig.class);
context.refresh();
九:Spring重要组件
接口BeanPostProcessor:拦截了所有中容器的Bean,并且可以进行bean的初始化-销毁(创建->初始化->使用->销毁)
- BeanPostProcessor:拦截容器中所有的bean
- BeanFactoryPostProcessor:拦截了容器本身(先拿到容器,再拿每个bean)
- BeanDefinitionRegistryPostProcessor:即将被加载之前被拦截(解析之前,称为BeanDefination对象之前)
BeanDefinitionRegistryPostProcessor(a) ->加载bean->BeanFactoryPostProcessor(b)->实例化bean->BeanPostProcessor
同一个方法 在不同地方(类、接口)的出现时机问题:a继承b,因此a中必然包含b中的方法(记c ):虽然a和b中都有c,但是 因此c出现的时机不同, 则c的执行顺序也不同: 如果是在a中出现,则先执行;如果是在b中出现 则后执行**
在同一个地方(类、接口),的不同方法的出现时机问题
监听器:也属于Spring组件
可以监听事件 ,监听的对象必须是 ApplicationEvent自身或其子类/子接口
- 方式一:通过接口实现
必须实现ApplicationListener接口 - 方式二:注解实现
@EventListener(classes = {ApplicationEvent.class})
(语法上 可以监听任意事件,但建议 ApplicationEvent自身或其子类/子接口)
注意:Spring:要让SPring识别自己,必须加入IOc容器(Bean+返回值| 注解+扫描器)
自定被监听事件:
- a.自定义类 实现ApplicationEvent接口(自定义事件)
- b.发布事件
context.publishEvent(自定义事件);
十:Quartz :定时异步任务
- 任务:做什么事情.... StudentService
- 触发器:定义时间
- 调度器:将任务、触发器 一一对应
实现步骤:(独立使用)
-
jar 使用2版本
任务(Serivce):把任务放入到JOb的实现类中
测试方法:Job 、 触发器 、调度器
scheduler.shutdown():立刻关闭
scheduler.shutdown(false):shutdown()立刻关闭
scheduler.shutdown(true):将当前任务执行完毕后 再关闭
触发器还可以用:CronScheduleBuilder
Cron表达式:
6-7个个参数,以空格隔开
秒 分 时 天(月) 月 天(周) (年)
2,10 3-6 12/3 L 2019-2022
Spring整合Quartz
jar
spring基础包(spring-context-support.jar/spring-tx.jar)+quartza.将Job信息封装到一个 实体类中
b.spring配置文件
调度器 ->触发器(Job、执行时间)