spring注解

一: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.形式区别:

  1. 三层组件加入IOC容器: 给个各类加注解 、 扫描器识别注解所在包
    a.给三层组件 分别加注解(@Controller、@Service、@Repository -> 如果不知道具体是哪层可以统一用:@Component)
    b.将注解所在包 纳入ioc扫描器(分两种)(ComponentScan)
    1. xml配置文件扫描器:
      com.likun.controller 用逗号分隔,同时也可以是com.likun扫描当前包,以及子包。
    2. 注解扫描器 在@Configuration注解上操作 @ComponentScan(value="com.likun”)


  1. 扫描器指定规则:本来是当前包和子包全部扫描。
    但现在可以指定:
    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)

  1. 非三层组件(ex:Student.class 、IntToStringConver.class):
    i. @Bean+方法的返回值 ,id默认就是方法名(可以通过@Bean("stu") 修改id值)
    ii. import 、FactoryBean(

二:bean的作用域

研究是不是单例

  1. 配置文件的方式: 有个属性是scope,可选为单例或者不单例 singleton| prototype,prototype原型或者叫做多实例
  2. 注解的方式:加一个注解@Scope("singleton”)

执行时机:(产生bean的时机):

  1. singleton:容器在初始化时,就会创建对象(唯一的一个);以后再getBean时,不再产生新的bean。singleton也支持延迟加载(懒加载):在第一次使用时产生。 @Lazy
    
  2. 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配置类中设置:

  1. 三层组件: 扫描器 + 三层注解
  2. 非三层组件:
    ① @Bean+返回值
    ②@import
    ③FactoryBean(工厂Bean)(spring底层提供)
    1. @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})
    2. FactoryBean(工厂Bean):
      ①准备bean。实现类和重写方法
      ②注册bean。注册到@Bean中,注意:需要通过&区分 获取的对象是哪一个 : 不加&,获取的是最内部真实的Apple和非三层中的(① @Bean+返回值)类似;如果加了&,获取的 是FacotryBean

五:Bean的生命周期

创建(new …)、初始化(赋初值 init)、 ....、销毁 (servlet destory)
IoC容器的生命周期:初始化容器、..使用容器、销毁容器。
注意:研究的是bean的生命周期:当单例模式的时候,容器会先自己创建一个对象,所以是先出现对象的无参构造,然后出现init方法,也就是初始化。
IoC容器在初始化时,会自动创建对象(构造方法) ->init ->.....->当容器关闭时 调用destroy…

  1. 方法一: Student.java 也就是可以被叫做bean的类
    适用于:@Bean+返回值方式
    init destroy
    ①xml方式:在bean中的属性中设置 init-method="myInit" destroy-method="myDestroy"
    ②注解: @Bean(value="stu",initMethod = "myInit",destroyMethod = "myDestroy”)

  1. 方法二:注解方式;适用于三层注解(是没有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值


  1. 方法三:接口方式:两个接口 接口:适用于三层组件(扫描器+三层注解)
    InitializingBean初始化
    DisposableBean 销毁
    初始化:只需要 实现InitializingBean中的afterPropertiesSet()方法
    销毁:实现DisposableBean 中的destroy()方法
    问题:要在SPring IOC容器中操作:选择哪种操作方式? 对象:Bean+返回 其他:三层组件,当前种类也是适用于三层组件
    小结:如果是注解形式 , 随便写一个方法 ,然后加上相应注解即可;如果是接口形式,必须 实现接口中规定的方法

  1. 方法四:接口方式:一个接口(给容器中的所有Bean加初始化、销毁重点是研究所有的bean包括了自己
    接口:同样适用于三层组件,在接口中可以对bean进行一些修改
    接口名字:BeanPostProcessor:拦截了所有中容器的Bean

六:自动装配 : 多用于三层组件(4个注解+扫描器)

Controller->Service->Dao

  1. 三层组件@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)
{
}

  1. Bean+返回值:@Autowired 可以放在方法的参数前(也可以省略 不建议使用),也可以放在方法前 (构造方法:特殊,如果只有一个有参构造方法,则构造方法前的@Autowired也可以省略 不建议使用
public void setXxx(@Autowired xx xx)
{
  
}

  1. 之前:@Autowired 根据类型(默认)匹配:三层注入方式/@Bean+返回值
    1.如果有多个类型相同的,匹配哪个?
    报错。 /加一个默认值 在相同的类型前其中一个加 @primary 然后就默认加载加了@primary的
    2.能否根据名字匹配?
    可以,结合 @Qualifier("stuDao2")使用。前提是对两个相同类型的实现类分别命名@Repository("stuDao2")
    3.如果有0个类型相同,默认报错;可以修改成不注入(null),@Autowired(required=false)

  1. 自动注入方式一: @Autowired (Spring提供) ,默认根据类型
    自动注入方式二:@Resource(JSR250:java规范),默认根据名字 (如果有名字,根据名字匹配;如果没有名字,先根据名字查找,如果没找到,再根据类型查找);也可以通过name或type属性 显示的指定根据名字 或类型找。
    自动注入方式三:@Inject(JSR330),额外引入javax.inject.jar,默认根据类型匹配

小结:单独的@Autowired根据类型使用,@Autowired加@Qualifier根据名字使用

七:利用Spring底层组件进行开发 (三层组件)

能够供我们使用的组件,都是Aware的子接口,即XxxxAware

  1. 以ApplicationContextAware为例:实现步骤
    a.实现ApplicationContextAware
    b.重写其中的方法,都包含了一个对象。只需要将该对象 赋值到属性中即可

有什么用:例如ApplicationContextAware,可以通过该接口 获取到Ioc容器对象。
执行时间: 如果在main()中new Ioc容器: 先执行ApplicationContextAware实现类中的方法,通过该方法传入IoC容器 供我们自己使用; 然后再将该容器通过new返回给用户

  1. BeanNameAware:

八:环境切换:@Profile

  1. 激活方式一:
    Dspring.profiles.active=@Profile环境名
    -Dspring.profiles.active=myApple
    例如:数据库环境:两种就可以来回切换
    @Profile
    127.0.0.1 scott tiger
    @Profile
    192.168...

  1. 激活方式二:
    硬编码
    坑:错误写法
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注解_第1张图片
bean加载时机.png

监听器:也属于Spring组件
可以监听事件 ,监听的对象必须是 ApplicationEvent自身或其子类/子接口

  • 方式一:通过接口实现
    必须实现ApplicationListener接口
  • 方式二:注解实现
    @EventListener(classes = {ApplicationEvent.class})
    (语法上 可以监听任意事件,但建议 ApplicationEvent自身或其子类/子接口)

注意:Spring:要让SPring识别自己,必须加入IOc容器(Bean+返回值| 注解+扫描器)

自定被监听事件:

  • a.自定义类 实现ApplicationEvent接口(自定义事件)
  • b.发布事件
    context.publishEvent(自定义事件);

十:Quartz :定时异步任务

  • 任务:做什么事情.... StudentService
  • 触发器:定义时间
  • 调度器:将任务、触发器 一一对应

实现步骤:(独立使用)

  1. jar 使用2版本


    spring注解_第2张图片
    12.png
  2. 任务(Serivce):把任务放入到JOb的实现类中

  3. 测试方法: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

  1. jar
    spring基础包(spring-context-support.jar/spring-tx.jar)+quartz

  2. a.将Job信息封装到一个 实体类中
    b.spring配置文件

调度器 ->触发器(Job、执行时间)

你可能感兴趣的:(spring注解)