spring ioc 学习笔记

spring ioc 学习笔记,第1张

spring ioc 学习笔记 Spring Ioc容器
  • 容器可以为我们的组件(类)提供一个完整的运行环境,可以帮助我们完成很多额外的 *** 作,有些类似与代理模式

    • 比如Controller中,我们只需要声明接口访问地址,传入的参数,返回的参数类型,就可以把重点放在我们的业务逻辑上,不需要去管解析HTTP协议等非常复杂的服务
    • 从类比关系上来看,Tomcat是一个Servlet容器,Docker是软件的容器
  • 从用法的层面来看,实现了一个类属性的创建

    • 如果我们平时有一个类,其中属性的初始化是不可避免的,很多时候,我们又需要单例模式,其实Ioc容器不止可以显示单例模式,但他是单例模式的一个很好的提现
    • 如果我们实例化的组件比较复杂,那么我需要编写大量的代码,而且不太美观,如果我们一个组件的初始化依赖另一个组件,那么这种复杂的关系就需要由我们手动编写代码去管理
    • spring一个注解就能帮助我们实现组件的管理,而且会帮助我们完成以下功能
      • 负责创建组件
      • 负责根据组件的依赖关系,组装组件
      • 在销毁的时候,按正确的依赖顺序销毁组件
    • 在这里,我们应该思考一个问题,怎么这些依赖关系的判断是怎么实现的,怎么创建和组装的
  • 什么是依赖注入

    • 就是把组件通过注解放在另一个组件并使用它,而且不需要知道他的创建细节
      • 所谓创建细节,就是我们在用一个对象的时候,我们首先要了解一个它都有哪些构造方法,然后我们看一下,它有哪些属性,因为除了静态方法以外,所有的方法基本都是围绕这些属性来展开的,这就是学习一个类的一般过程
      • 当然,当类涉及到继承接口等关系时,我们也要了解一下,可以利用idea直接可视化出整个继承的关系
  • 什么是控制反转

    • 以前是由编程人员来控制对象的创建,但是过程比较重复和繁琐,控制反转就是把创建对象的控制权,交给spring,由spring来控制这些对象的创建流程
  • 依赖注入和控制反转都是Ioc,依赖注入更偏向于Ioc的运用,控制反转,更偏向于Ioc的设计思想

  • spring用注解帮助我们实现了Ioc,我们发现这种注解的方法,对代码的入侵极小,比如我们在使用权限框架的时候,如果采用注解授权,我们会发现很方便,一点也不影响我们的逻辑代码,比如我现在的代码只能由管理用,但是我们把注解删了,或换成其他的,我的代码一点也不需要变,但权限很轻松的改变了

    • 这里有个小问题,就是这个的方式自己写起来比较爽,但是这样接口和权限的耦合性还是比较大的,如果我们的接口分布在多个应用中,那我们的每个应用都需要有权限模块
    • 还有一个比较大的问题就是,这样的设计,我们是无法实现权限的实时修改,比如一个接口,我想让普通用户也有访问权限,这就需要修改代码
  • 早期spring用xml的方式装配bean

    ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
    UserService userService = context.getBean(UserService.class);
    
  • 我们可以通过注解指定扫描的范围,如果这些范围内有注解,那么就装配,否则就不管,这样看起来效率很高,而且可以采用约定大于配置的思想,这样就不需要指定要扫描的包,那么这样有个问题,如果我们要扫码的包在外部,那怎么办呢

    • 我们可以在包内弄一个组件,在这个组件中创建外部的对象,然后装配到里面
    • 如果没有自动装配,我们可以理解为,其他的库的组件,其实都是不起作用的必须要我们自己去扫描
    • 我们会发现两件事情
      • 这个里面有很多重复的工作
      • 重复的工作里面有好多特定的配置
    • 重复中带有特殊配置,自动装配(帮助我们写重复代码),yaml配置,很好的可读性(处理特殊的配置),而且yaml也是有默认参数的
  • @Scope

    • 如果你的单例模式,默认组件,有非静态变量,很可能会产生线程安全的问题,所以这些组件不能出现写的 *** 作,读配置文件,在启动的时候完成,其他情况都是写,是没有什么问题的

      • 谈一下在启动的时候,执行某些代码,我们可以放在spring boot启动的main函数里面,在main函数里面的那行代码执行完成之后,就是启动完成的时候,这个时候程序已经启动完成,可以正常使用了,不需要担心其他的问题
    • 除了每次获取bean可以获得一个新的对象以为,我们可以弄成一个请求生成一个,一个用户对应一个自己的专属对象(这个需要借助session,不是很好)

    • ioc注入甚至能注入list

      • 定义一个接口,用几个类去实现它,给这些类表上注解,目前来看,其实和单个没有任何区别

      • 所以关键是注入的方式

        • @Autowired
          List validators;
          
        • 这多可能的名字,所以spring是用接口来对应注入哪个的

        • 而且当我们又通过接口实现一个类以后,spring会自动帮我们把这些类都放进这个list中,而我们不需要做任何修改,这就是设计模式的完美提现

      • 那么多list项,我们怎么指定他们的顺序呢,答案是Order

  • @Autowired(required = false)

    • 这个注解是spring提供的,@Resource是Java提供的注解,这个唯一好处就是指定名字好指定,我们用这个一般是因为他不报错,看起来比较舒服

    • required=false的意义就是,如果我们找到了要装配的,就用装配的,否则就用默认的

    • @Autowired(required = false)
      ZoneId zoneId = ZoneId.systemDefault();
      
    • 这样就可以实现有定义就使用定义,没有就使用默认值的情况

    • 总的来说,这两个在普通的项目中,互相替换是完全没有问题的,但是autowired肯定是比resource功能强大的

  • 我们可以自定义一些构建比较复杂的对象,用@Bean就可以实现

  • 简单的生命周期

    • @PostConstruct
      public void init() {
          System.out.println("Init");
          //初始化
      }
      
      @PreDestroy
      public void shutdown() {
          //执行比如关闭链接池的方法
      }
      
    • 执行流程

      • 调用无参数构造方法创建实例,所以默认无参构造器,对于框架来说,是非常重要的,因为他们是类反射方式创建对象中最简单的办法
      • 根据属性的注解,比如@Autowired进行属性的注入
      • 然后用@PostConstruct注解的方法初始化
      • 而在销毁的时候,会执行@PreDestory,所以有Pre
      • 这些方法必须是无参数方法,最好的解释就是,用这个对于反射来说,很简单,而且也没有必要,且很难弄参数,执行
  • 别名

    • @Bean
      ZoneId createZoneOfZ() {
          return ZoneId.of("Z");
      }
      
      @Bean
      ZoneId createZoneOfUTC8() {
          return ZoneId.of("UTC+08:00");
      }
      
    • 上面我们创建了两个ZoneId

    • 报错NoUniqueBeanDefinitionException,说明spring是根据返回值来确定注入类型的

    • 那么我们想配置多个,比如多数据源,那怎么办呢

      • @Bean("z")
        ZoneId createZoneOfZ() {
        	return ZoneId.of("Z");
        }
        
      • 别名,区分重复,互相代替命名(注解中的value)

      • 但是,还会报错 NoUniqueBeanDefinitionException: No qualifying bean of type ‘java.time.ZoneId’ available: expected single matching bean but found 2

      • 因为我在设置的时候弄了两个,但是注入的时候没有指定它是谁

      • 怎么办?指定就可以@Qualifier(“z”)

      • 但是,这样真的好吗

        • 我们配置多数据源肯定不是一开始就要的,所以,在一开始,我们弄了特别多的注入,现在,我们必须要一个一个改注入的名称
        • @Primary
        • 指定为主要的,如果存在多个,但是使用的时候没有指定,就用这个
        • 这样对以前的代码就没有入侵
        • 如果我们的好多不确定性 *** 作(不知道以后会写什么代码),能由程序编写代码帮助我们实现扩充
          • 比如用反射实现的工厂模式,我们甚至一行代码都没有改,就是自己加了一个类
  • 我们还可以可以通过工厂方法创建bean,详见廖老师的博客

  • 如果我们想要装配的是一个文件Resource文件注入

    • classpath:xxx,maven目录结构说绝对的,在resource里面放这些资源文件
    • file:xxx指定全目录,按linux的指定就行,亲测在window上,会等效成你d盘的某个目录
  • 这个bean在spring中的默认名称,就是首字母小写的驼峰命名

  • @value的小技巧

    • 写普通注入的时候,可以用${},你可能会好奇,为什么每次都要写这个呢,因为他有别的注入方法
    • #{xxxBean.xxx属性} 可以读取其他bean的值,其实我们可以把这个bean注入,但是这样少了手写获取的程序
  • bean的条件装配 根据不同的条件,决定是否要创建某个Bean

欢迎分享,转载请注明来源:内存溢出

原文地址: https://outofmemory.cn/zaji/5637534.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存