近来在做web开发,从spring开始做一些简单的学习。

下面是一些基本的spring概念,在学习时逐步记录下来。

Spring框架学习记录

Spring核心思想

  • IOC: inversion of control 控制反转。
    • 把创建对象new,对象依赖关联关系交给容器去处理,目的解耦合。
    • 我们常见的bean对象,就是交给spring容器管理的对象。Bean默认是单例的,在spring加载时候默认就会创建这些bean对象,无论你用不用,都存在。
    • 我们可以通过修改xml中的bean class值,达到修改关联实现类的作用。例如A类中有个B类的对象,这种注入关系,也受到spring的自动管理。
  • DI: Dependency Injection 依赖注入
    • 运行过程中,动态向其他对象提供其依赖关联对象。其实现机制使用反射。
  • AOP:Asepct-Orentid Programming 面向切面编程

部分注解

* @Component 表示该类需要在应用程序中被创建,受到spring容器管理,无需额外new
        需要写到实现类上,不要写到接口类上
        要解决单接口多继承实现类的歧义性,可使用
            1. @Primary 提高实现bean类的优先级,只能有一个primary
            2. @Qualifier("xxoo") 别名限定符,在component处声明别名,在autowired进行@Qualifier动态绑定
            3. @Component("xxoo") 和上面一样,bean id限定符,在component处声明别名,在autowired进行@Qualifier动态绑定
            4. 不指定Qualifier别名,也不指定Component的bean id,使用空id的@Component,则默认bean id是  类名首字母小写。使用时候依然在autowired进行@Qualifier动态绑定
            5. 当函数参数类型为父接口类,实现不明时,可以用 @Qualifier("xxoo")来修饰参数,以保证参数为指定子类型对象。
            6. 还可以使用 javax 的 Resource(name="xxoo"),来替代spring的 Autowired + Qualifier 做动态绑定
        compenent属于基本组件类,为符合web的三层结构,controller -> service -> dao ,所以现在推荐使用 @Controller @Service @Respository 三个业务功能注解,不推荐使用 @Compenent,但对不起,这三个新玩意儿和compenent本质上没区别,就是一个区别功能性的注释。
* @ComponentScan 表示自动发现该应用程序中需要被创建的类,自动扫描需要创建类
        注意,默认仅扫描本类所在包以及子包内的compenent。
        如需扫描其他包。
            1. 需要后面追加包名,例如 @ComponentScan("com.xxoo.project.package") 
            2. 或者 @ComponentScan(basePackages = {"com.xxoo.project.package1", "com.xxoo.project.package2"}),用来添加多包
            3. 或者@ComponentScan(basePackageClasses = {MyClass1.class, MyClass2.class}),这种方式方式是,当我们修改包名时不用修改代码
* @Autowired 自动满足bean之间的依赖,自动装配,自动依赖注入。
    使用环境
        可适用于构造函数,未使用反射,最为高效
        也可适用于setter方法以及普通方法
        也可使用于成员变量,最为方便
    特殊属性
        required=true/false
* @Configuration 表示该类当前是一个配置类,可以做到main和组件扫描进行分离

自动装配方式

​ 三种

  • 隐式自动装配【推荐】

    • 对类标注 @component注解,该类会被作为组件类,spring对该类创建 bean对象

    • 然后,一般创建一个空的配置类,该类进行 @componentScan 注解,该类必须为 @Configuration 类,表示spring将自动扫描该配置类所在包。然后在main中,使用 @ContextConfiguration 去加载配置类来进行使用,使用如下

    @ContextConfiguration(classes = AppConfig.class)
    
    • 一般配套使用 @autowired 进行bean自动装配依赖,加(required=false)进行控制;Qualifier来设置bean的id

    • 通常会注入构造函数或者setter方法

  • java显式装配

    • 一般是因为第三方库,我们不能修改去源代码加标注。这是需要显式的进行装配。

    • 通常先创建一个javaconfig类,里面不放业务逻辑代码,专门配置所需的bean,例如

    @Configuration
    @ContextConfiguration(locations = {"classpath:spring/spring-dao.xml","classpath:scan.xml"})
    public class bbsConfig{
      private Postdao postdao;
      private Userdao userdao;
      @Bean(name="postservice")
       public PostService getPost()
      {
        return new PostserviceImpl(postdao,userdao);
      }
    }
    
    • 此时,@Bean 对configration配置类中,@bean表示需要被自动装配的对象

    其使用方式,以及去除多义性的方式和自动装配一模一样。@bean 几乎等同于 @Component, 区别仅仅是后者修饰类(我们有源码,可以修改类代码),而前者@bean修饰一个函数(通常在appConfig配置类中),用这个函数创建第三方类对象。

  • XML配置方式【不太推荐】,就是在XML文件里面对bean做配置,实现自动依赖注入。一般叫 applicationContext.xml. 格式固定,例如

  <?xml version="1.0" encoding="UTF-8"?>
  <beans xmlns="http://www.springframework.org/schema/beans"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns:context="http://www.springframework.org/schema/context"
         xsi:schemaLocation="http://www.springframework.org/schema/beans
          http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
      ">
      <!--
          这里就是scan的子包名,相当于 @ComponentScan, 这是XML中启动扫描的方法
      -->
      <context:component-scan base-package="com.freeknight.demo" />
      <!--
        这部分描述需要被管理的组件名,相当于 @bean
          bean: 描述当前对象需要被spring对象管理
          id: 从spring容器中获取对象时候使用该id
          class: 需要被管理的对象类别全名
      -->
      <bean id="service" class="service.MessageService">
      </bean>
      <bean id="printer" class="service.MessagePrinter">
          <!-- 
            这部分描述依赖关系,可以不用额外手动指定。
              name 是函数参数名
              ref 是上面声明的bean id
           -->
          <property name="service" ref="service"></property>
      </bean>
  </beans>
  • 其中 bean id 就是bean对象的名字,唯一。
  • 其中 bean name是bean的别名,可以有多个别名,用分号空格逗号分开都可以。通过任何一个别名都可以获得对应的bean对象。
  • 其中可以通过元素进行构造函数的依赖注入。同样可以缩减为 “c-” 命名空间。
    • 可以复杂类型注入,包括 list, set, map, array, 以及对象ref,基本类型使用 value
  • 也可以通过元素进行属性注入,一般是利用set get方法。一样可以缩减为 “p-” 命名空间。
  • 还可以用 util- 命名空间 来做一些普通数据的定义,以方便 p- 注入。

注入后的使用如下:

  @ContextConfiguration("classpath:applicationContext.xml")

高级装配

  • Bean的Scope作用域

    • 前提知识

    • Bean默认是单例的,无论你获取多少次,拿到的都是一个对象。

    • 但有些时候,我们希望Bean不是单例的,每次获取时能是一个新的对象,我们可以通过设定bean的作用于scope来达成,scope有四个值

    • singleton 默认,单例,只有一个bean实例

    • prototype 原型模式,每次注入或通过getbean上下文获取时,都会创建一个新的bean实例

    • session 会话模式,在web应用中,每个会话会创建一个bean实例

    • request 请求模式,在web应用中,对每个请求会创建一个bean实例

    • 限制scope

    • XML中

      <bean id="xxoo" class="com.freeknight.demo.xxoo" scope="singleton">
      </bean>
    
    • JAVA自动装配中
      @Component
      @Scope("session") // 或者@Scope(ConfigurableBeanFactory.SCOPE_SESSION)均可
      public class MyClass{ }
    
    • JAVA手动装配中
      @Configration
      public class AppConfig{
        @Bean
        @Scope("session")
        public MyClass getMyClass(){
            return new MyClass();
        }
      }
    
  • 延迟加载

    • 前提知识:

    • 在spring加载时候默认就会创建这些bean对象,无论你用不用,都存在。

    • 但有些时候我们不想开始花费时间进行bean对象创建和加载,我们需要使用时按需加载,则需要使用延迟加载,我们就需要使用 lazy-init

    • 注意:lazy延迟加载仅对singleton的scope有效,对于另外三种scope,默认就已经是lazy-init。

    • 延迟加载Lazy-init (该值默认为false; 设置为true则会开启延迟加载)

    • XML中

      <bean id="xxoo" class="com.freeknight.demo.xxoo" lazy-init=“true”>
      </bean>
    
    • JAVA自动装配中
      @Component
      @Lazy
      public class MyClass{ }
    
    • JAVA手动装配中
      @Configration
      public class AppConfig{
        @Bean
        @Lazy
        public MyClass getMyClass(){
            return new MyClass();
        }
      }
    
  • Bean对象的初始化和销毁函数

    • 当spring进行bean对象创建和销毁时,希望自动调用我们的初始化和释放函数.

    • 假设有一个JAVA类

    public class MyClass{ 
        public void myInit(){
                
        }
        public void myDestory(){
                
        }
    }
    
    • 使用时

    • XML中

      <bean id="xxoo" class="com.freeknight.demo.xxoo" destory-method="myDestory" init-method="myInit">
      </bean>
    
    • JAVA自动装配中
      @Component
      public class MyClass{ 
          @PostConstruct
          public void myInit(){
                  
          }
          @PreDestory
          public void myDestory(){
                  
          }
      }
    
  • 工厂方法创建bean对象

    • 静态工厂方法 和 实例工厂方法

    • 假设我们有一个类

    public class Person{}
        
    public class PersonFactory{
        public static Person createPersonS(){
            return new Person();
        }
        public Person createPersonI(){
            return new Person();
        }
    }
    
    • 使用时

    • XML中

      <!-- 静态工厂 -->
      <bean id="Person1" class="com.freeknight.demo.PersonFactory" factory-method="createPersonS">
      </bean>
      <!-- 实例工厂 -->
      <bean id="PersonFactory" class="com.freeknight.demo.PersonFactory" />
      <bean id="Person2" factory-bean="PersonFactory" factory-method="createPersonI"/>
    

其他扩展

  • log4j 添加pom的dependence,修改log4j.properties

  • junit 添加pom的dependence,在test目录下创建同名包,添加 @Test 函数测试

  • spring-test 添加pom的dependence,在test目录下创建同名包,添加 @RunWith(SpringJUnit4ClassRunner.class),加载配置类 @ContextConfiguration(classes=AppConfig.class)

spring, spring MVC, spring boot, spring cloud关系和区别

  • spring
    • 是一个大框架,包括众多衍生品,包括 spring boot, spring mvc, security, jpa等。但都基于IOC和AOP。
    • IOC提供依赖注入的容器,AOP解决面向切面的编程。
  • spring MVC
    • 是一个基于servlet的MVC框架,用来处理web开发的路径映射和视图渲染,解决WEB开发问题。
    • 它是spring框架里,关于web层开发的一部分
    • 一般网页服务开发,会分为三层。WEB层 -> service层 -> dao层 -> 数据库
    • 它和struts1, struts2平级,同样功能。
  • spring boot

    • 为了简化spring开发者的使用,而出来的一套快速开发整合包。它增加了约定大于配置理念,快速集成多个 spring插件。
    • 约定大于配置 :就是说如果没有做配置,就会使用默认配置,只有不符合默认值的配置,才需要额外配置。目的是让开发者减少复杂配置。
    • 它专注于开发微服务后台接口,不负责前端视图的开发。
  • spring cloud

    • 基于 spring boot 开发实现的一套云应用开发工具,它依赖于spring boot。
    • spring boot更关注于单一微服务开发,但spring cloud更关注于将spring boot开发的微服务进行整合和管理,它包括服务发现注册,配置中心,消息总线,负载均衡,断路器,数据监控,一键启动部署等功能。

spring boot基本概念

  • 特点

    • 和spring一起诞生的微框架,上手简单,配置依赖少(不用xml)
    • 可以不依赖容器(war包),直接独立运行
    • 可以可视化监控和性能检查等
    • 支持一个简单的 starter 依赖项,直接懒人包全部配置好(会略有依赖库的冗余)
  • 用途

    • 一般用在web项目中
    • 一般用在微服务开发
  • 入门流程

    // demo1application.java
    @SpringBootApplication
    public class Demo1Application {
        public static void main(String[] args) {
            SpringApplication.run(Demo1Application.class, args);
        }
    }
    
    // 一个简单的controller
    @RestController
    public class HelloController {
        @RequestMapping("/hello")
        String index() {
            return "Hello Spring Boot";
        }
    }
    
    • 运行 demo1application.java,本地访问 localhost:8080/hello 进行API测试

吐槽

这一切完全就是新瓶装老酒,我发现现在的技术 都特喜欢起新名词。

  • 为了解耦,把反射机制做了个规范化,使用注释和XML配置方法实现,这就是IOC,DI。
  • 啥TMD“约定大于配置”啊,任何一个ini config类,都有defaultvalue好吗?
  • 我一直讨厌小语法糖,看起来的确似乎可以省点事,但最终你都要去了解去本质,逃不掉的。但记住大量语法糖的规则,还需要浪费很多注意力。spring里面就大量的语法糖,恶心。
  • Bean的管理看起来很甜,问题是下面如何的对象管理都交给了别人,真的好不放心。原本java只是管理内存,现在都开始做对象管理了,很好。
  • 简直是标注狂+配置狂,下一步应该是自动化代码生成工具吧?类似unreal的blueprint?
  • 真能分层啊,view facade service dao mapper简直让人应接不暇,满地图的设计模式。