spring

# spring介绍

1、spring是什么?  

一个开源的用来简化应用开发的框架。

spring是J2EE应用程序框架,是轻量级的IoC和AOP的容器框架,主要是针对javaBean的生命周期进行管理的轻量级容器,可以单独使用,也可以和Struts框架,ibatis框架等组合使用。

2、作用

  ##简化开发

    spring对常用的api做了封装和简化(比如,对jdbc做了封装,使用spring jdbc来访问数据库,就不用考虑获取连接和关闭连接。)

  ##简化管理

    spring提供一个容器。帮我们创建以及建立对象之间的依赖关系

    好处:降低对象之间的耦合度,方便代码的维护

  ##集成其他框架

    spring可以将其它的一些框架集成进来。(比如,集成用于任务调度的框架Quartz)。

  QQ截图20190226122512image

1)IoC(Inversion of Control)控制反转,对象创建责任的反转,在spring中BeanFacotory是IoC容器的核心接口,负责实例化,定位,配置应用程序中的对象及建立这些对象间的依赖。XmlBeanFacotory实现BeanFactory接口,通过获取xml配置文件数据,组成应用对象及对象间的依赖关系。

spring中有三种注入方式,一种是set注入,一种是接口注入,另一种是构造方法注入。

2)AOP面向切面编程

   aop就是纵向的编程,业务1和业务2都需要一个共同的操作,与其往每个业务中都添加同样的代码,不如写一遍代码,让两个业务共同使用这段代码。

spring中面向切面编程的实现有两种方式,一种是动态代理,一种是CGLIB,动态代理必须要提供接口,而CGLIB实现是有继承

# 为什么使用spring框架

  在不使用spring框架之前,我们的service层中要使用dao层的对象,不得不在service层中new一个对象。如下:

//dao层对象
public class UserDao{
   publicvoid insert(User user){}
}
 
//service层对象
public classUserService{
   publicvoid insert(User user){
       UserDaouserdao = new UserDao();
       userdao.insert(user);
   }
}

存在的问题:层与层之间的依赖。

使用框架后:

//dao层对象
public class UserDao{
    public void insert(User user){}
}
//service层对象
public class UserService{
   private UserDao userdao;
 
   public UserDao getUserdao() {
      returnuserdao;
   }
   public void setUserdao(UserDao userdao) {
      this.userdao= userdao;
   }
   public void insert(User user){
      userdao.insert(user);
   }
}

service层要用dao层对象需要配置到xml配置文件中,至于对象是怎么创建的,关系是怎么组合的都交给了spring框架去实现。

4、框架优点

轻量级的容器框架没有侵入性

使用IoC容器更加容易组合对象直接间关系,面向接口编程,降低耦合

Aop可以更加容易的进行功能扩展,遵循ocp开发原则

创建对象默认是单例的,不需要再使用单例模式进行处理

5、缺点:业务功能依赖spring特有的功能,依赖于spring环境

# spring容器(IOC)

##什么是spring容器?

spring框架的一个核心模块,用于管理对象。容器将创建对象,把它们连接在一起,配置它们,并管理他们的整个生命周期从创建到销毁。

Spring 容器使用依赖注入(DI)来管理组成一个应用程序的组件。这些对象被称为 Spring Beans。IOC 容器负责实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。

下图是 Spring 如何工作的高级视图。 Spring IoC 容器利用 Java 的 POJO 类和配置元数据来生成完全配置和可执行的系统或应用程序。

##Spring 提供了两种不同类型的容器。

Spring BeanFactory 容器

它是最简单的容器,给 DI 提供了基本的支持,它用 org.springframework.beans.factory.BeanFactory 接口来定义。BeanFactory 或者相关的接口,如 BeanFactoryAware,InitializingBean,DisposableBean,在 Spring 中仍然存在具有大量的与 Spring 整合的第三方框架的反向兼容性的目的。

Spring ApplicationContext 容器

该容器添加了更多的企业特定的功能,例如从一个属性文件中解析文本信息的能力,发布应用程序事件给感兴趣的事件监听器的能力。该容器是由 org.springframework.context.ApplicationContext 接口定义。

注:ApplicationContext 容器包括 BeanFactory 容器的所有功能,所以通常建议超过 BeanFactory。

##启动spring容器

step1:导包。(spring-webmvc)

step2:添加配置文件。

step3:启动spring容器。

##创建对象

方法1:使用无参构造器

           1.给类添加无参构造器(或者缺省构造器)

           2.配置<bean>元素。

           3.调用容器的getBean方法来获得对象。

方法2:使用静态工厂方法

           通过调用类的静态方法来创建对象。

方法3:使用实例工厂方法

          通过调用对象的实例方法来创建对象。

package first;
public class Student {
    public Student() {
        System.out.println("Student()");
    }
}
package first;
public class FirstSpring { public static void main(String[] args) { //1.启动spring容器 ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
Student stu = ac.getBean("stu1",Student.class);
System.out.println(stu);
Date date = ac.getBean("date",Date.class);
System.out.println(date);
Calendar cal1 = ac.getBean("cal1",Calendar.class);
System.out.println(cal1);
Date time1 = ac.getBean("time1",Date.class);
System.out.println(time1);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="" xmlns:xsi=""xmlns:context="" xmlns:jdbc="" xmlns:jee="" xmlns:tx="" xmlns:aop="" xmlns:mvc="" xmlns:util="" xmlns:jpa="" xsi:schemaLocation="">
    <!-- 使用无参构造器创建对象。 id属性:bean的名称,要求唯一。 class属性:类的全限定名(即要求包名)。 -->
    <bean id="stu1" class="first.Student"></bean>
    <bean id="date" class="java.util.Date"></bean>
    <!-- 使用静态工厂方法创建对象   factory-method属性:指定一个静态方法。  spring容器会调用这个静态方法来创建对象。 -->
    <bean id="cal1" class="java.util.Calendar" factory-method="getInstance"></bean>
    <!-- 使用实例工厂方法创建对象   factory-bean属性:指定一个bean的id。  factory-method属性:指定一个方法,spring容器会调用这个bean的对应的方法来创建对象。 -->
    <bean id="time1" factory-bean="cal1" factory-method="getTime"></bean>
</beans>

##作用域

默认情况下,容器对于某个bean,只会创建一个实例。

可以设置scope属性值为prototype,这样,容器对于某个bean会创建多个实例。

package scope;
public class ScopeBean {
    public ScopeBean() {
        System.out.println("ScopeBean()");
    }
}
<!-- scope属性:用来配置作用域,缺省值是singleton(单例), 如果值为prototype(原型)。-->
<bean id="s1" class="scope.ScopeBean" scope="prototype"/>
package test;public class TestCase {
    @Test//测试作用域
    public void test1() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("scope.xml");//启动spring容器
     //创建对象
     ScopeBean s1 = ac.getBean("s1",ScopeBean.class);
     ScopeBean s2
= ac.getBean("s1",ScopeBean.class);
     System.out.println(s1
== s2);
  }
}

测试结果:  ScopeBean()

       false


##生命周期

初始化方法:

  使用init-method属性来指定初始化方法名。

销毁方法:

  使用destroy-method属性来指定初始化方法名。

注:spring容器在关闭前,会销毁对象,在销毁对象之前,会先调用对象的销毁方法。

package scope;
public class MessageBean {
    public MessageBean() {
        System.out.println("MessageBean()");
    }
    public void init() {
        System.out.println("init()");
    }
    public void sendMsg() {
        System.out.println("sendMsg()");
    }
    public void destroy() {
        System.out.println("destroy()");
    }
}
<!-- init-method属性:指定初始化方法。
         destroy属性:指定销毁方法。 -->
    <bean id="mb1" class="scope.MessageBean" init-method="init" destroy-method="destroy" />
@Test
    //测试生命周期
    public void test2() {
        //ApplicationContext 接口
        //ClassPathXmlApplicationContext 实现类
        //AbstractApplicationContext 是ApplicationContext的子接口
        AbstractApplicationContext ac = new ClassPathXmlApplicationContext("scope.xml");
        MessageBean mb1 = ac.getBean("mb1",MessageBean.class);
        mb1.sendMsg();
        ac.close();
    }

###延迟加载

spring容器启动后会将所有作用域为单例的bean创建好。

注:只有作用域为单例时,销毁方法才会执行。

<!—lazy-init属性:指定是否延迟加载,如果为true,表示延迟加载。 -->
<bean id="mb1" class="scope.MessageBean" init-method="init" destroy-method="destroy" 
    lazy-init="true" />

##IOC

###什么是IOC?

对象之间的依赖关系由容器来建立。

###DI(依赖注入)

容器通过调用对象提供的set方法构造器来建立依赖关系。

IOC是目标,DI是手段。

1.set方式注入

package ioc;

public class A {

    private IB ib;
    
    public void setB(IB ib) {
        System.out.println("setB()");
        this.ib = ib;
    }

    public A() {
        System.out.println("A()");
    }
    
    public void execute() {
        System.out.println("execute()");
        ib.f1();
    }

}
package ioc;
public class B implements IB {

    public B() {
        System.out.println("B()");
    }
    
    public void f1() {
        System.out.println("B's f1()");
    }

}

package ioc;
public class C implements IB {

    public C() {
        System.out.println("C()");
    }
    
    public void f1() {
        System.out.println("C's f1()");
    }

}

package ioc;
public interface IB {
    public void f1();
}
<bean id="b1" class="ioc.B" />
    <bean id="c1" class="ioc.C"></bean>
    <!-- 
        property元素:表示使用set方法注入依赖关系。
        其中,name属性指定属性名,ref属性指定属性值(是被注入的bean的id)
     -->
    <bean id="a1" class="ioc.A">
        <property name="b" ref="b1"></property>
    </bean>
@Test
    //测试set方式的注入
    public void test5() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("ioc.xml");
        A a1 = ac.getBean("a1",A.class);
        a1.execute();
    }

QQ截图20190305204805

2.构造器方法

package ioc2;
public class A {

    private B b;
    
    public A() {
        System.out.println("A()");
    }
    
    public A(B b) {
        System.out.println("A(B)");
        this.b = b;
    }

    public void execute() {
        System.out.println("execute()");
        b.f1();
    }
}
package ioc2;
public class B {

    public B() {
        System.out.println("B()");
    }
    
    public void f1() {
        System.out.println("B's f1()");
    }
}
<bean id="b1" class="ioc2.B" />
    <!-- 
        constructor-arg元素:用来配置构造器方式的注入,其中,
        index属性指定参数的下标(从0开始)。
     -->
    <bean id="a1" class="ioc2.A">
        <constructor-arg index="0" ref="b1"></constructor-arg>
        <!-- <constructor-arg index="1" ref="c1"></constructor-arg> -->
    </bean>
@Test
    public void test1() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("ioc2.xml");
        A a1 = ac.getBean("a1",A.class);
        a1.execute();
    }

3.自动装配

指的是spring容器依据某种规则,自动建立对象间的依赖关系。

注:a.默认情况下,容器不会自动装配。

      b.可以通过指定autowire属性,来告诉容器进行自动装配

       (容器仍需要通过set方法或构造器来完成依赖关系的建立)。

package ioc2;

public class Waiter {

    public Waiter() {
        System.out.println("Waiter()");
    }
}
package ioc2;

public class Restaurant {

    private Waiter wt;
    
    public void setWt(Waiter wt) {
        System.out.println("setWt()");
        this.wt = wt;
    }

    public Restaurant() {
        System.out.println("Restaurant()");
    }

    @Override
    public String toString() {
        return "Restaurant [wt=" + wt + "]";
    }
}
<!-- 
        autowire属性:自动装配,有3个属性值:
        byName:容器依据属性名查找对应的bean,然后调用对应的set方法来完成注入。
                注:a.如果找不到对应的bean,注入null。
                    b.不可能找到多个符合条件的bean。
        byType:容器依据属性类型查找对应的bean,然后调用对应的set方法来完成注入。
                注:a.如果找不到对应的bean,注入null。
                    b.有可能找到多个符合条件的bean,此时会出错。
        constructor:与byType类似,不同的是调用对应的构造器来完成注入。
     -->
    <bean id="wt" class="ioc2.Waiter"></bean>
    <!-- <bean id="rest" class="ioc2.Restaurant" autowire="byName" /> -->
    <bean id="rest" class="ioc2.Restaurant" autowire="byType" />
@Test//测试自动装配
    public void test2() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("ioc2.xml");
        Restaurant rest = ac.getBean("rest",Restaurant.class);
        System.out.println(rest);
    }

###注入基本类型的值(使用value属性即可)

<bean id="vb1" class="value.ValueBean">
        <property name="name" value="张三"></property>
        <property name="age" value="30"></property>
    </bean>

###注入集合类型的值(List Set Map Properties)

package value;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class ValueBean {
    private String name;
    private int age;
    private List<String> city;
    private Set<String> interest;
    private Map<String,Double> score;
    private Properties db;
    public ValueBean() {
        System.out.println("ValueBean()");
    }
    public void setScore(Map<String, Double> score) {
        this.score = score;
    }
    public void setDb(Properties db) {
        this.db = db;
    }
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setCity(List<String> city) {
        this.city = city;
    }
    public void setInterest(Set<String> interest) {
        this.interest = interest;
    }
    @Override
    public String toString() {
        return "ValueBean [name=" + name + ", age=" + age + ", city=" + city + ", interest=" + interest + ", score="
                + score + ", db=" + db + "]";
    }
}
<bean id="vb1" class="value.ValueBean">
        <property name="name" value="张三"></property>
        <property name="age" value="30"></property>
        <property name="city">
            <list>
                <value>北京</value>
                <value>南京</value>
                <value>西京</value>
            </list>
        </property>
        <property name="interest">
            <set>
                <value>小说</value>
                <value>小品</value>
            </set>
        </property>
        <property name="score">
            <map>
                <entry key="english" value="60"></entry>
                <entry key="math" value="66"></entry>
            </map>
        </property>
        <property name="db">
            <props>
                <prop key="username">Tiger</prop>
                <prop key="password">1234</prop>
            </props>
        </property>
    </bean>
@Test
    public void test3() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("value.xml");
        ValueBean vb1 = ac.getBean("vb1",ValueBean.class);
        System.out.println(vb1);
    }

输出:ValueBean()
ValueBean [name=张三, age=30, city=[北京, 南京, 西京], interest=[小说, 小品], score={english=60.0, math=66.0}, db={password=1234, username=Tiger}]

###将集合类型的值配置成一个bean

<!-- 将集合类型的值配置成一个bean -->
    <util:list id="cityBean">
        <value>上海</value>
        <value>武汉</value>
        <value>深圳</value>
    </util:list>
    <!-- 引用的方式注入集合类型的值 -->
    <bean id="vb2" class="value.ValueBean">
        <property name="city" ref="cityBean"></property>
    </bean>
@Test
    public void test4() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("value.xml");
        ValueBean vb2 = ac.getBean("vb2",ValueBean.class);
        System.out.println(vb2);
    }

list、set、map、properties的情况和list相仿,此处不做重复。

###读取properties文件的内容

<!-- 
        读取properties文件的内容
        classpath:按照类路径来搜索。
        spring容器会依据路径找到对应的properties文件,
        然后读取该文件的内容到properties对象。
     -->
    <util:properties id="config" location="classpath:config.properties"></util:properties>
pagesize=10
@Test
    public void test5() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("value.xml");
         Object config = ac.getBean("config");
        System.out.println(config);
    }

###spring表达式

可以使用spring表达式读取其它bean的属性,它的语法类似于el表达式。

QQ截图20190306222019

原文地址:https://www.cnblogs.com/menbozg/p/10469996.html