Spring学习笔记-spring基础知识概述

参考:网络资料。

  • spring简介
    spring是目前最流行的开发框架,不论是web项目还是CS项目都能看到spring的身影,这是因为spirng提供了很多常用的组件的同时,不会强制你去使用它们。spring利用两大核心技术(DI 依赖注入和AOP面向切面编程)实现应用程序各模块之间的高度解耦,spring封装了在开发过程中的很多通用模块,大大提高了应用的开发效率。

  • spring的优点
    1)低侵入式设计,代码污染低
    2)独立于各种应用服务器,基于spring框架的应用可以实现一次编写多次运行。
    3)spring的ioc容器降低了业务对象替换的复杂性,实现了组件时间的解耦合
    4)spring的aop支持了将很多通用任务如安全、事务、日志等进行集中处理,从而提高了代码的复用性,通过减小了核心业务代码的复杂性。
    5)spring高度开放,并不强制应用完全依赖于spring,可以自由选择用spring框架的部分功能。

  • spring框架的组成结构
    Spring学习笔记-spring基础知识概述_第1张图片

  • spring的核心机制

    1.管理bean
    spring容器负责创建、装配和配置对象,并且对他们的声明周期进行管理,容器是spring框架的核心。Spring容器使用依赖呼入管理构成应用组件,它创建互相协作的组件之间的关系。

    常用的spring容器入口有三种:
    ClassPathXmlApplicationContext:从类路径下的xml配置文件中加载上下文定义,吧应用上下文定义文件当做资源文件。

    FileSystemXmlApplicationContext:读取文件系统下的xml配置文件并加载上下文定义。

    XmlWebApplicationContext:读取web应用下的xml配置文件并装载上下文定义。

  • 依赖注入
    spring框架的核心功能有两个
    1)Spring容器作为超级大工厂,负责创建,管理所有Java对象,这些Java对象被称为bean。
    2)Spring容器管理容器中bean之间的依赖关系,Spring使用一种被称为依赖注入的方式来管理 bean之间的依赖管理,使用依赖注入不仅可以为bean注入普通的属性值,还可以注入其他bean的引用。依赖注入是一种优秀的解耦方式,其可以让bean以配置文件的方式组织在一起,而不是以硬编码的方式耦合在一起。

    理解依赖注入:
    当某个Java对象需要调用另外一个Java对象的方法时,传统 模式下通常有两种做法
    1)调用者手动创建被依赖对象,然后再调用被依赖对象的方法
    2)还有一种常用方式就 是利用工厂模式,调用者先找到被依赖对象的工,然后主动通过工厂去获取被依赖对象,最后在调用被依赖对象的方法。
    这两种调用都是主动方式,会导致调用者与被依赖对象之间的耦合,非常不利于项目的升级和维护,使用spring框架之后,调用者无需主动获取被依赖对象,只要被动接受spring容器为调用者的称为变量赋值即可,由此可以见,使用spirng容器后,调用者获取被依赖对象的方式由原来的主动获取变成了被动接受。

    另外从spring容器的角度来看,spring容器负责将被依赖对象赋值给调用者的成员变量,相当于为调用者注入了它的依赖实例。

    依赖注入的方式最常用的有以下两种,
    1)利用setter方法注入
    这种方式简单直接,因而在spring的依赖注入中大量使用。

<bean id="simpleBeanTwos" class="com.spring.test.di.SimpleBeanTwo"/>
      <bean id="simpleBeanThree" class="com.spring.test.di.SimpleBeanThree">
          <property name="simpleBeanTwos" ref="simpleBeanTwos"/>
      </bean>
2)利用构造器注入
这种方式就是驱动spring在底层一反射的方式执行带指定参数的构造器,当执行带参数的构造器时,就可以利用构造器参数对程序变量进行初始化。
<bean id="movieFinder" class="com.spring.test.di.MovieFinder"/>
<!-- 一个参数 -->
<bean id="simpleMovieLister" class="com.spring.test.di.SimpleMovieLister">
           <constructor-arg ref="movieFinder"/>
</bean>
这两个注入方式 的对比
setter注入有以下优势:
1)与传统的javabean的写法相似,程序开发人员更容易理解,通过setter方法设置依赖关系,显得很直观很自然。
2)对于复杂依赖,如果采用构造器注入,会导致构造器过于臃肿,难以阅读,Spring在创建bean实例时,需要同时实例化其他依赖的全部实例,会导致性能下降。
3)在某些成员变量为可选的情况下,多参数的构造器显得更加笨重


      利用构造器的方式注入有以下优势:
      1)构造器注入可以在构造器中决定依赖关系的注入顺序,
      2)对于依赖关系无需变化的bean,利用构造器注入更加简洁,无需写入很多setter方法。
      3)依赖关系只能 在构造器总设定,则只有组件的创建者才能改变组件的依赖关系,对㢟的调用者而言,组件内部的依赖关系完全透明,符合高内聚低耦合的原则。

实际开发中,尽量采用setter注入为主,构造器注入为辅。对于依赖关系无需变化的注入,尽量采用构造器注入,而其他关系的注入则考虑采用setter注入。
  • Spring中的bean
    对于开发者莱索,使用spring框架主要做两件事:1)开发bean 2)配置bean。对于spring框架来说,它要做的就是根据配置文件来创建bean实例,并调用实例方法完成依赖注入。

    当通过spring容器创建一个bean实例时,不仅可以完成bean的实例化,还可以为bean指定特定的作用域,Spring支持五种作用域:

    1)singleton:单利模式,在整个spring Ioc容器中,singleton作用域的bean将只能生产一个实例。

    2)prototype:每次通过容器的getBean()方法获取prototype作用域 bean时,将产生一个新的bean实例。
    3)rquest:对于每次http请求,request作用域的bean将只产出一个实例,这就是说,在痛一次http请求内,程序每次请求该bean,总是得到同一个实例,只有在web中使用spring容器时才会使用到该作用域。
    4)session:对于痛一次会话,值产生一个bean的实例,这意味着在同一次http会话内,程序内存访问bean,得到的总是同一个实例,只有在web应用中使spring时,该作用域才能起作用。
    5)global session:每个局部的http Session对应一个bean实例,在典型的情况下,仅在使用portlet context时才有效(web项目)。

    如果不制定bean的作用域spring默认使用singleton作用域,prototype作用域的bean实例创建、销毁代价都比较大,而singleton作用域的bean实例一点创建成功,就可以重复使用。因此应避免将bean的作用域设置成prototytpe作用域。

  • 利用自动装配简化配置文件
    Spring能自动装配bean与bean之间的依赖关系,即无需使用ref显示指定依赖bean,而是由Spring容器检查xml配置文件内容,根据某种规则,为调用者bean注入依赖的bean。

    Spring自动装配可以通过beans标签的default-autowire属性指定,该属性对配置文件中的所有bean元素起作用,也可以通过对bean元素的autowire属性指定,该属性只对bean起作用。

    autowire和default-autowire可以接受如下值
    1)no:不使用自动装配。bean依赖必须通过ref元素定义。这是默认配置,在较大的部署环境中不鼓励改变这种配置,显示配合作者能够得到更清楚的依赖关系。
    2)byName:根据setter方法名进行自动装配,spring容器查找容器中的全部bean,找出其id与setter方法名去掉setter前缀,并小写首字母后面的bean来完成注入,如果没有找到匹配bean的实例,则spring不进行注入。
    3)byType:根据setter方法的形参类型来自动装配。Spring查找容器中的全部bean,如果正好有一个bean类型与setter方法的形参类型匹配,就自动注入这个bean,如果找到多个这样的bean,就是抛出异常;如果没有找到这个bean,则什么也不会发生,setter方法不会被调用。
    4)constructor:与byType相似,区别是用于自动匹配构造参数。如果容器不能恰好找到一个与构造参数匹配的bean,则会抛出异常。

    5)autodetect:spring容器根据bean内部是结构,自动决定使用constructor或者byType策略。先按constructor,在按byType进行自动装配。

     当一个bean即使用自动装配依赖,又使用ref显示指定依赖时,则显示指定的依赖覆盖自动装配的依赖;对于大型应用不鼓励使用自动装配,虽然自动装配可以减少配置文件的工作,但大大将死了依赖关系的清晰性和透明性,依赖关系的装配依赖于文件的属性名和属性类型会导致bean与bean时间的耦合关系降低到代码层次,不利于高层次解耦。
    
  • 创建bean的三种方式
    1)使用构造器创建bean
    使用构造器来创建bean实例是最常见的方式,如果不采用构造注入,spring地层会调用bean的无参构造函数,来创建实例,因此要求bean类提供无参构造函数。

 <bean id="testBean" name="testBeanName" class="com.spring.test.entity.TestEntity"/> 
 2)使用静态工厂创建bean
 使用静态工厂创建bean时,class属性必须制定,但此时class属性并不是指定bean实例的实现类,而是静态工厂类,spring通过该属性知道由哪个工厂类创建bean实例。
 此外,还需要使用factory-method属性来指定静态工厂方法,spring调用静态工厂方法返回一个bean的实例,一单获得的指定bean的实例,spring后面的处理步骤与采用普通方法创建bean实例完成一样,如果静态工厂方法需要参数,则使用`<constructor-args\>`元素来指定静态工厂的方法参数。
<bean id="testFactoryBean" class="com.spring.test.beanfactory.StaticBeanFactory"
            factory-method="testBeanFactory"/>
3)使用实例工厂创建bean
实例工厂方法与静态工厂方法只有一个不同:调用静态工厂方法值需要使用工厂类即可,而调用实例工厂方法则需要工厂实例,使用实例工厂方法时,配置bean实例的bean元素无需class属性,配实例工厂方法使用factory-bean指定工厂实例。
<bean id="factoryBean" class="com.spring.test.beanfactory.InstanceBeanFactory"/>
     <bean id="instanceFactoryBean" factory-bean="factoryBean" factory-method="getTestEntity"/>
  • 协调作用域不同的bean
    当singleton作用域的bean依赖于rototype作用域的bean时,会产生不同步的现象,原因是因为当spring容器启动时,容器会预初始化容器中所有的singleton bean,由于singleton bean依赖于prototype bean,因此spring容器在初始化singleton bean之前,会先创建prototype bean,然后才创建singleton bean,接下来将prototype bean注入到singleton bean中。

    解决不同步的方法有两种:
    1)放弃依赖注入:singleton作用域的bean每次需要prototype作用域的bean时,主动向容器请求新的bean实例,即可保证每次注入的prototype bean实例是最新的实例。

    2)利用方法注入
    方法通常使用lookup方法注入,使用lookup方法注入可以使spring容器重写与容器中bean的抽象或具体方法,返回查找容器中其他bean的结果,被查找的bean通常是一个non-singleton bean,spring通过使用jdk动态代理或者cglib库修改客户端的二进制文件,从而实现上述要求。

    建议采用第二种方法,使用方法注入,为了使用lookup方法注入,大致需要如下两步:
    ①将调用者bean的实现类定义为抽象类,并定义一个抽象方法来获取被依赖bean
    ②在bean标签中添加lookup-method子元素,使sring为调用者bean实现类实现指定的抽象方法。

public static class I{
        public void doSomething(){
            System.out.println("I do something.");
        }
}
public static abstract class K{

        public void process(){
            I i = createAnotherBean();
            i.doSomething();
            System.out.println(i);
        }

        protected  abstract I createAnotherBean();
}

<bean id="k" class="com.spring.test.temp.A$K">
           <lookup-method name="createAnotherBean" bean="i"/>
</bean>
  • Spring的零配置支持
    1)所搜bean
    Spring2.5以后,提供了一下几个注解来注册bean类到spring容器
    @Component:标注一个普通的Spring Bean类
    @Controller:标注一个控制器组件类
    @Service:标注一个业务逻辑组件类
    @Repository:标注一个Dao组件类

    在Spring配置文件中做如下配置,指定自动扫表包及其子包,spring会自动扫描这些包下被以上注解标注的Bean类到sprig容器中

<context:component-scan base-package="com.spring.test">

2)使用@Autowired或@Resource注解进行装配
@Autowired是Spring提供的装配注解,可以标注在setter方法、构造器或成员变量上,实现依赖的自动注入

@Autowired
public void setInstrument(Instrument instrument){
     this.instrument = instrument;
}

或
@Autowired
public Instrument(Instrument instrument){
     this.instrument = instrument;
}

或 
@Autowired
private Instrument instrument;

@Resource是jdk提供的标准的依赖注入注解,利用这个注解可以进一步实现代码与spring的解耦,但更常用的是@Autowired,以为一个基于spring的应用很少会迁移到别的平台。
用法与@Autowird相同。

  • Spring的AOP
    AOP也就是面向切面编程,它作为面向对象编程的一种补充,已经成为一种比较成熟的编程方式。
    AOP专门用于处理系统中分布在不同模块中的交叉关注点的问题,在javaEE的应用中经常通过aop来处理一些横切性质的系统级服务,如事务管理,安全检查和缓存,AOP已经成为一种非常常用的解决方案。

    使用AspectJ实现AOP
    AspectJ是一个基于Java语言的aop框架,提供了强大 的aop功能,主要包含两个部分,一个部分定义了如果表达、定义编程中的语法规范,通过这套规范可以方便的运用aop来解决java语言中存在的交叉关注点问题,另一部分是工具,包括编译 和调整等。
    同时,spring本身也提供了一套完整aop解决方案。

    AOP中的基本概念

    切面:切面即是一个关注点,切面用于组织多个通知,通知放在切面中。
    通知:通知定义了切面是什么和在何处使用。

    连接点:程序执行过程中明确的一点,比如方法调用,或者抛出异常。
    切点:切点用于定义吧切面放在何处,它与通知一起完整的说明了切面。

    使用spring aop前,需要在配置文件中添加aop支持的声明
    
 <aop:aspectj-autoproxy/>

下面是一个将事务配置成切面的例子:

<!-- transaction aspect -->
<bean id="transaction" class="com.spring.test.proxy.Transaction"/>
<aop:config>
  <aop:pointcut expression="execution(* com.spring.test.dao.impl.AopPersonDaoImpl.*(..))" id="perform"/>
     <aop:aspect ref="transaction">
      ///通知
     </aop:aspect>
</aop:config>

你可能感兴趣的:(spring,开发框架)