博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Spring学习笔记1——Spring基础及组件使用
阅读量:3943 次
发布时间:2019-05-24

本文共 11609 字,大约阅读时间需要 38 分钟。

Spring简介

  1. Spring是一种开源轻量级框架,是为了解决企业应用程序开发复杂性而创建的,Spring致力于解决Java EE的各层解决方案,而不仅仅于某一层的方案。

  2. 可以说Spring是企业应用开发的“一站式”选择,Spring贯穿于表现层、业务层、持久层,然而Spring并不想取代那些已经有的框架,而是以高度的开放性,与这些已有的框架进行整合

  3. Spring是一个全面的解决方案,它坚持一个原则:不重新造轮子。已经有较好解决方案的领域,Spring绝不重复性实现,比如:对象持久化和OR映射,Spring只对现有的JDBCHibernate等技术提供支持,使之更容易使用,而不做重复的实现。Spring框架有很多特性,这些特性由7个定义良好的模块构成:

    • Spring Core:即,Spring核心,它是框架最基础的部分,提供IOC和依赖注入特性。
    • Spring Context:即,Spring上下文容器,它是BeanFactory功能加强的一个子接口。
    • Spring Web:它提供Web应用开发的支持。
    • Spring MVC:它针对Web应用中MVC思想的实现。
    • Spring DAO:提供对JDBC抽象层,简化了JDBC编码,同时,编码更具有健壮性。
    • Spring ORM:它支持用于流行的ORM框架的整合,比如:Spring+HibernateSpring+iBatisSpring+JDO的整合等等。
    • Spring AOPAOP即,面向切面编程,它提供了与AOP联盟兼容的编程实现。
  4. Spring常用组件:

    在这里插入图片描述

xml配置与@Configuration注解配置

  1. xml配置方式:

    beans.xml主要代码如下:

    测试类主要代码如下:

    public class MainTest1{
    public static void main(String args[]){
    // 把beans.xml中的类加载到容器中 ApplicationContext app = new ClassPathXmlApplicationContext("beans.xml"); // 从容器中获取bean Person person = (Person) app.getBean("person"); System.out.println(person); }}
  2. 注解配置方式:

    配置类主要代码如下:

    // 配置类,相当于配置文件@Configurationpublic class MainConfig{
    // 给容器中注册一个bean,类型为返回值的类型 @Bean public Person person(){
    return new Person("yhl",19); }}

    测试类主要代码如下:

    public class MainTest2{
    public static void main(String args[]){
    ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig.class); // 从容器中获取bean Person person = (Person) app.getBean("person"); System.out.println(person); }}
  3. @Configurationbeans.xml作用一样,@Configuration更简单、灵活

@ComponentScan扫描规则

  1. 可以定制包扫描时的过滤规则,比如,以下代码会扫描出@ControllerBookService

    @Configuration@ComponentScan(value="com.study.spring",includeFilters={
    @Filter(type=FilterType.ANNOTATION,classes={
    Controller.class}), @Filter(type=FilterType.ASSIGNABLE_TYPE,classes={
    BookService.class})},useDefaultFilters=false) public class MainConfig2 {
    // 给容器中注册一个bean,类型为返回值的类型 @Bean public Person person01(){
    return new Person("yhl",19); }}
  2. @ComponentScan注解的属性:

    • value:指定要扫描的包。
    • excludeFilters = Filter[]:指定扫描的时候按照什么规则排除哪些组件。
    • includeFilters = Filter[]:指定扫描的时候只需要包含哪些组件。
    • useDefaultFilters = false:默认是true扫描所有组件,要改成false,才能使用自定义扫描范围。
  3. @Filter的扫描规则如下:

    • FilterType.ANNOTATION:按照注解,比如@Controller@Service@Repository@Component注解。
    • FilterType.ASSIGNABLE_TYPE:按照给定的类型,比如BookService类型。
    • FilterType.ASPECTJ:使用ASPECTJ表达式。
    • FilterType.REGEX:使用正则指定。
    • FilterType.CUSTOM:使用自定义规则,自已写类,实现TypeFilter接口。
  4. 自定义规则示例:

    public class YhlTypeFilter implements TypeFilter{
    private ClassMetadata classMetadata; /* * MetadataReader:读取到当前正在扫描类的信息 * MetadataReaderFactory:可以获取到其他任何类的信息 */ @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException{
    // 获取当前类注解的信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); // 获取当前正在扫描的类信息 classMetadata = metadataReader.getClassMetadata(); // 获取当前类资源(类的路径) Resource resource = meatadataReader.getResource(); String className = classMetadata.getClassName(); System.out.println("--->" + className); // 当类包含er字符,则匹配成功,返回true if(className.contains("er")){
    return true; } return false; }}
    @Configuration@ComponentScan(value="com.study.spring",includeFilters={
    @Filter(type=FilterType.CUSTOM,classes={
    YhlTypeFilter.class})},useDefaultFilters=false) public class MainConfig2 {
    // 给容器中注册一个bean,类型为返回值的类型 @Bean public Person person(){
    return new Person("yhl",19); }}

@Scope扫描规则

  1. @Scope注解的值:

    • prototype:多实例,IOC容器启动的时候并不会取调用方法创建对象,而是每次获取的时候才会调用方法创建对象。
    • singleton:单实例(默认),IOC容器启动的时候会调用方法创建对象并放到IOC容器中,以后每次获取的就是直接从容器中拿的同一个bean
    • request:主要针对web应用,递交一次请求创建一个实例。
    • session:同一个session创建一个实例。
  2. 没加@Scope之前, 默认的bean是单实例的。

  3. 比如,以下代码指定bean为多实例:

    @Configurationpublic class MainConfig3{
    // 给容器中注册一个bean,类型为返回值的类型,默认是单实例 @Scope("prototype") @Bean public Person person(){
    return new Person("yhl",19); }}

@Lazy懒加载

  1. 主要针对单实例bean(单实例bean默认在容器启动的时候创建对象),使用懒加载后,容器启动的时候不创建对象,仅当第一次使用(获取)bean的时候才创建并初始化。

  2. 示例如下:

    @Configurationpublic class MainConfig4{
    // 给容器中注册一个bean,类型为返回值的类型,默认是单实例 @Lazy @Bean public Person person(){
    return new Person("yhl",19); }}

@Conditional条件注册bean

  1. 当引入@Conditional时, 容器可以选择性的注册bean。比如,当操作系统为WINDOWS时,注册yhl1实例; 当操作系统为LINUX时, 注册yhl2实例:

    // 配置类@Configurationpublic class MainConfig5{
    @Conditional({
    WinCondition.class}) @Bean("yhl1") public Person yhl1(){
    return new Person("yhl1",19); } @Conditional({
    LinuxCondition.class}) @Bean("yhl2") public Person yhl2(){
    return new Person("yhl2",20); }}
    // 条件类,必须得实现Spring提供的Confition接口public class WinCondition implements Condition{
    /* * ConditionContext: 判断条件能使用的上下文(环境) * AnnotatedTypeMetadata: 注释信息 */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    // 能获取到IOC容器正在使用的beanFactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 获取当前环境变量(包括操作系统时WIN还是LINUX) Environment environment = context.getEnvironment(); String os_name = environment.getProperty("os.name"); if(os_name.contains("Windows")){
    return true; } return false; }}
    // 条件类,必须得实现Spring提供的Confition接口public class LinCondition implements Condition{
    /* * ConditionContext: 判断条件能使用的上下文(环境) * AnnotatedTypeMetadata: 注释信息 */ @Override public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
    // 能获取到IOC容器正在使用的beanFactory ConfigurableListableBeanFactory beanFactory = context.getBeanFactory(); // 获取当前环境变量(包括操作系统时WIN还是LINUX) Environment environment = context.getEnvironment(); String os_name = environment.getProperty("os.name"); if(os_name.contains("linux")){
    return true; } return false; }}
  2. FactoryBeanBeanFactory的区别:可以把Java实例bean通过FactoryBean注入到容器中;BeanFactory从容器中获取实例化后的bean

@Import注册bean

  1. 给容器注册组件的方式

    • @Bean:导入第三方的类或包的组件,比如Person为第三方的类,需要在IOC容器中使用。
    • 包扫描+组件的标注注解@ComponentScan@Controller@Service@Repository@Component):一般是针对自己写的类,使用这个。
    • @Import:快速给容器导入一个组件。@Bean有点简单。
      • @Import(要导入到容器中的组件):容器会自动注册这个组件,beanid为全类名
      • ImportSelector:是一个接口,返回需要导入到容器的组件的全类名数组
      • ImportBeanDefinitionRegistrar:可以手动添加组件到IOC容器,所有bean的注册可以使用BeanDefinitionRegistry,写YhlImportBeanDefinitionRegistrar实现ImportBeanDefinitionRegistrar接口即可
    • 使用Spring提供的FactoryBean(工厂Bean)进行注册:容器调用getObject()返回对象,把对象放到容器中;getObjectType()返回对象类型;isSingleton()是否单例进行控制。新建YhlFactoryBean实现FactoryBean,在config里新建yhlFactoryBean()方法。
  2. 使用@Importdogcatbean注册到容器中:

    @Configuration// 导入组件,ID默认是组件的全类名@Import(value = {
    Dog.class,Cat.class})public class MainConfig6 {
    // 容器启动时初始化person的bean实例 @Bean public Person person(){
    return new Person("yhl",19); }}
  3. ImportSelector可以批量导入组件的全类名数组,自定义逻辑返回需要导入的组件:

    public class YhlImportSelector implements ImportSelector{
    @Override public String[] selectImports(AnnotationMetadata importingClassMetadata){
    // 返回全类名的bean return new String[]{
    "com.study.spring.Fish","com.study.spring.Tiger"}; }}
    @Configuration@Import(value = {
    Dog.class,Cat.class,YhlImportSelector.class})public class MainConfig7 {
    // 容器启动时初始化person的bean实例 @Bean public Person person(){
    return new Person("yhl",19); }}
  4. 通过ImportBeanDefinitionRegistrar自定义注册,向容器中注册bean

    public class YhlImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    /* * AnnotationMetadata:当前类的注解信息 * BeanDefinitionRegistry:BeanDefinition注册类,把所有需要添加到容器中的bean加入 * 调用BeanDefinitionRegistry.registerBeanDefinition自定义手工注册进来 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    boolean bean1 = registry.containsBeanDefinition("com.study.spring.Dog"); boolean bean2 = registry.containsBeanDefinition("com.study.spring.Cat"); // 如果Dog和Cat同时存在于IOC容器中,那么创建Pig类,加入到容器 if(bean1 && bean2){
    // 以前的bean都是全类名,现在自定义bean名 // 对于要注册的bean,需要给bean进行封装 RootBeanDefinition beanDefinition = new RootBeanDefinition(Pig.class); // 注册一个bean,bean名为pig registry.registerBeanDefinition("pig", beanDefinition); } }}
    @Configuration@Import(value = {
    Dog.class,Cat.class,YhlImportSelector.class,YhlImportBeanDefinitionRegistrar.class})public class MainConfig8 {
    // 容器启动时初始化person的bean实例 @Bean public Person person(){
    return new Person("yhl",19); }}
  5. 通过实现FactoryBean接口方式来加载bean

    public class YhlFactoryBean implements FactoryBean
    {
    @Override public Monkey getObject() throws Exception {
    return new Monkey(); } @Override public Class
    getObjectType() {
    return Monkey.class; } @Override public boolean isSingleton() {
    return true; }}
    @Configurationpublic class MainConfig9 {
    @Bean public YhlFactoryBean yhlFactoryBean(){
    return new YhlFactoryBean(); }}

    默认获取到的是工厂bean调用getObject创建的对象,要获取工厂bean本身,需要在id前加个yhlFactoryBean

bean生命周期

  1. bean的生命周期是指**bean创建-----初始化----销毁**的过程,是由容器进行管理的。

  2. 可以自定义 bean初始化和销毁方法:容器在bean进行到当前生命周期的时候, 来调用自定义的初始化和销毁方法,有3种方式:

    • 指定初始化和销毁方法:

      • beans.xml中可以指定init-methoddestory-mothod

      • 用注释的话,在配置类里通过@Bean(initMethod="init",destroyMethod="destroy")指定。

        @Bean(initMethod="init", destroyMethod="destory")public Bike bike(){
        return new Bike();}

        单实例:当容器关闭的时候,会调用destroy消耗。

        多实例:容器只负责初始化,但不会管理bean,容器关闭不会调用销毁方法。

    • Bean实现InitializingBeanDisposableBean接口:

      • InitializingBean(定义初始化逻辑):afterPropertiesSet()方法:当beanFactory创建好对象,且把bean所有属性设置好之后,会调这个方法,相当于初始化方法。
      • DisposableBean(定义销毁逻辑):destory()方法,当bean销毁时,会把单实例bean进行销毁。
      @Componentpublic class Train implements InitializingBean, DisposableBean{
      public Train(){
      System.out.println("Train......constructor............"); } // 当bean销毁时,调用此方法 @Override public void destroy() throws Exception {
      System.out.println("Train......destory......"); //logger.error } // 当bean属性赋值和初始化完成时调用 @Override public void afterPropertiesSet() throws Exception {
      System.out.println("Train.......afterPropertiesSet()..."); }}
    • 使用JSR250规则定义的(java规范)两个注解来实现:

      • @PostConstruct:在bean创建完成,且赋值完成后进行初始化,属于JDK规范的注解。
      • @PreDestroy:在bean将被移除之前进行通知,在容器销毁之前进行清理工作。
      @Componentpublic class Jeep {
      public Jeep(){
      System.out.println("Jeep.....constructor........"); } @PostConstruct public void init(){
      System.out.println("Jeep.....@PostConstruct........"); } @PreDestroy public void destory(){
      System.out.println("Jeep.....@PreDestroy......"); }}
  3. BeanPostProcessor类(interface)是bean的后置处理器,负责在初始化方法前后进行一些处理工作:

    • postProcessBeforeInitialization():在初始化之前进行后置处理工作(在init-method之前)。在任何初始化方法调用之前调用此方法(比如在InitializingBeanafterPropertiesSet初始化之前,或自定义init-method调用之前使用)。
    • postProcessAfterInitialization():在初始化之后进行后置处理工作,比如在InitializingBeanafterPropertiesSet()之后。
    /* * 后置处理器:初始化前后进行处理工作 * 将后置处理器加入到容器中 */@Componentpublic class YhlBeanPostProcessor implements BeanPostProcessor{
    @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("postProcessBeforeInitialization...."+beanName+"..."+bean); // 返回一个对象(传过来的对象),也可包装好再返回 return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("postProcessAfterInitialization...."+beanName+"..."+bean); return bean; }}

转载地址:http://briwi.baihongyu.com/

你可能感兴趣的文章
find border vertex
查看>>
matlab sliced variable
查看>>
create symbolic array
查看>>
TAUCS库的编译(vs2010)
查看>>
color vector using in plotting example points and lines between corresponding vertices
查看>>
mex 里面调用matlab函数
查看>>
matlab中cuda编程中分配grid和block dimension的时候的注意事项
查看>>
GPU CUDA and MEX Programming
查看>>
arrayfun用法
查看>>
矩阵积分
查看>>
optimization on macOS
查看>>
Template-Based 3D Model Fitting Using Dual-Domain Relaxation
查看>>
install libfreenect2 on ubuntu 16.04
查看>>
how to use automake to build files
查看>>
using matlab drawing line graph for latex
查看>>
How package finding works
查看>>
build opencv3.3.0 with VTK8.0, CUDA9.0 on ubuntu9.0
查看>>
how to compile kinfu_remake with cuda 9.0 opencv2.4.13.4
查看>>
qtcreator4.4.1中cmake 与cmake3.5.1本身generate出来的setting是有区别的解决方法
查看>>
ubuntu下解决csdn网页打不开的问题
查看>>