Spring框架

一、Spring框架概述

1、Spring是一个service层的框架,可以整合许多其他框架进行工作。

2、Spring的主要技术:

(1)IOC(DI)

控制反转(依赖注入):低耦合——代码分离、便于代码复用

(2)AOP

面向切面编程:高内聚——结构清晰、便于开发维护

二、控制反转(低耦合)

由Spring框架管理对象创建和生命周期的机制称为控制反转

spring框架源码 spring框架入门教程_xml

1、创建Spring的project

spring框架源码 spring框架入门教程_spring框架源码_02

2、导入jar包

spring框架源码 spring框架入门教程_创建对象_03

3、创建Spring的xml配置文件

spring框架源码 spring框架入门教程_xml_04


4、配置Person类

id

标识配置的这个bean的类名

class

标识配置这个类的全路径

<bean id="person" class="cn.tedu.domain.Person">

5、Spring实现IOC的底层原理

@Test
public void test02(){
    //1、初始化容器:发现配置文件开始解析Spring配置文件
    ApplicationContext context= new ClassPathXmlApplicationContext("applicationContext.xml");
    //2、通过Spring容器创建对象,获取person类
    Person person =(Person)context.getBean("person");
    person.eat();
    person.sleep();
    //3、关闭Spring容器
    //ClassPathXmlApplicationContext有close();ApplicationContext没有close()
    ((ClassPathXmlApplicationContext)context).close();
}

spring框架源码 spring框架入门教程_java_05

推论一:可以多次获取同一个id的bean,获取到的值相同
推论二:不能配置多个id相同的bean
推论三:可以配置多个class相同但id不同的bean
6、获取对象的方式:
(1)通过id获取对象(常用)

Person p = (Person)context.getBean("person");//cn.tedu.domain.Person@65e

找到唯一

返回对象

找不到

NoSuchBeanDefinitionException

找到多个

不可能,id是唯一标识

(2)通过class获取对象

Person p1 = context.getBean(Person.class);

找到唯一

返回对象

找不到

再找该类型的子孙类型的bean,找到则返回子孙对象

都找不到

NoSuchBeanDefinitionException

找到多个

有可能找到多个,抛出异常NoUniqueBeanDefinitionException

(3)指定id别名
name:指定对应的bean的id,alias指定新id

<alias name="person" alias="person2"></alias>

7、创建Spring对象
Spring创建对象的本质:通过类的无参构造器来创建对象。
(1)无参构造

<bean id="person" class="cn.tedu.domain.Person"></bean>

实现原理:在Spring容器初始化时,通过上配置的class属性反射得到字节码文件,在通过newInstance()创建实例对象。这种创建方法的类中只能有无参构造方法,否则无法使用反射。
(2)有参构造
实现原理:通过配置bean的参数,实现控制Spring容器通过指定的构造器创建对象,而不是通过默认的无参构造器

index

三者不需要都设置,没有歧义即可 有参构造的第几个参数,0开始

name

参数名

type

参数类型

value

二选一 赋予的具体指(基本数据类型或者String类型)

ref

赋予值(引用数据类型)

配置文件

<bean id="person2" class="cn.tedu.domain.Person2">
    <constructor-arg index="0" name="name" type="java.lang.String" value="lili"></constructor-arg>
    <constructor-arg index="1" name="age" type="int" value="10"></constructor-arg>
</bean>

Person2

public Person2(String name,int age){
    System.out.println("person2,name:"+name+",age:"+age);
}

Test

//有参构造创建对象
@Test
public void test05(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    Person2 p = (Person2)context.getBean("person2");
    System.out.println(p);
    ((ClassPathXmlApplicationContext)context).close();
}

spring框架源码 spring框架入门教程_spring框架源码_06


(3)静态工厂

实现原理:因为要使用指定的静态方法来实例化对象,就得将静态工厂类中的无参构造方法私有化。

通过工厂创建对象:如果创建出来的对象需要经过若干设置后才能使用,spring也支持通过工厂创建bean。

工厂设计模式:就是通过一个工厂类将创建对象的细节封装起来,之后通过工厂创建对象,简化创建对象的过程。

NetConn.java

public class NetConn {//实现连接好网络后查询数据的功能
    public void load(){   System.out.println("加载配置文件...");  }
    public void ping(){ System.out.println("测试网络..."); }
    public void conn(){System.out.println("连接网络...");}
    public void login(){System.out.println("登录...");}
    public void sendData(){System.out.println("发送数据..."); }
}
NetConnStaticFactory.java
public class NetConnStaticFactory {//创建工厂类,将网络连接和登录操作封装起来
private NetConnStaticFactory(){}//私有化无参构造方法
    public static NetConn getNetConn(){//创建NetConn类的对象
        NetConn nc = new NetConn();//通过nc调用这些方法,完成方法的封装
        nc.load();
        nc.ping();
        nc.login();
        return nc;
    }
}

applicationContext.xml

<!-- 配置静态工厂方法目的:通过指定的静态工厂方法创建对象
此时已经发生了操作 NetConn conn=NetConnStaticFactory.getNetConn();-->
<bean id="nc" class="cn.tedu.domain.NetConnStaticFactory" factory-method="getNetConn"></bean>

TestDemo.java

public void test01(){
    //前提假设:使用NetConn类的对象直接调用sendData(),不需要连接检查操作
    //加载配置文件
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    //获取bean:拿到Spring容器创建好的实例对象conn
    //nc的数据类型需是NetConn,后续才能使用该对象直接调用sendData()方法
    NetConn nc =(NetConn) context.getBean("nc");
    nc.sendData();
    //关闭Spring容器
    ((ClassPathXmlApplicationContext)context).close();
}

spring框架源码 spring框架入门教程_spring框架源码_07

(4)实例工厂
实现原理:实例工厂中的方法不是静态的,所以不能直接调用自定义的工厂方法来实例化对象。(因为.xml先于.java文件加载)所以先配置工厂对象的bean,底层创建出一个工厂对象后,再配置自定义工厂方法就可以实例化对象。
NetConnInstanceFactory.java

public class NetConnInstanceFactory {
    private NetConnInstanceFactory(){}//私有化无参构造方法
    public NetConn getNetConn(){//创建非静态工厂方法
        NetConn nc = new NetConn();
        nc.load();
        nc.ping();
        nc.login();
        return nc;
    }
}

applicationConext.xml

<bean id="NetConnInstanceFactory" class="cn.tedu.domain.NetConnInstanceFactory"></bean>
<!-- 相当于给netConn也准备了一个实例对象-->
    <bean id="netConn" factory-bean="NetConnInstanceFactory" factory-method="getNetConn"></bean>

TestDemo.java

public void test02(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    //获取id为NetConn的bean标签(相当于获取实例化好的NetConn对象)
    NetConn netConn = (NetConn) context.getBean("netConn");
    netConn.sendData();
    ((ClassPathXmlApplicationContext)context).close();
}

spring框架源码 spring框架入门教程_创建对象_08

(5)Spring工厂
实现原理:让普通工厂实现FactoryBean接口;在工厂类中实现生产对象的创建;然后在.xml文件中配置bean-id、bean-class,就能实例化对象。
NetSpringFactory.java

public class NetConnSpringFactory implements FactoryBean<NetConn> {
      @Override  //创建生产目标
    public NetConn getObject() throws Exception {
        NetConn nc = new NetConn();
        nc.load();
        nc.ping();
        nc.conn();
        nc.login();
        return nc;
    }
       @Override //获取目标对象的类型
    public Class<?> getObjectType() { return NetConn.class; }
        @Override//控制生产目标对象是否是单例
    public boolean isSingleton() {return false;}
}

applicationContext.xml

<bean id="nc" class="cn.tedu.domain.NetConnSpringFactory"></bean>

TestDemo.java

@Test
public void test03(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    NetConn nc = (NetConn)context.getBean("nc");
    nc.sendData();
    ((ClassPathXmlApplicationContext)context).close();
}

spring框架源码 spring框架入门教程_java_09

(6)单例、多例

spring框架源码 spring框架入门教程_spring框架源码_10

(7)懒加载机制

在单例标签上配置lazy-init=true会设置为懒加载模式,在此模式下不会在容器初始化时创建bean对象,而是在第一次使用对象时创建,从而减少了容器启动的时间和空间的消耗。

懒加载只对单例bean标签生效(懒加载本身就是多例);懒加载只是延后了对象创建的时机,对象仍然是单例的。

全局

spring框架源码 spring框架入门教程_xml_11


局部

<bean id="person" class="cn.tedu.domain.Person" lazy-init="false"></bean>

同时设置则就近生效局部的
(8)Spring实现配置自定义的初始化、销毁方法

<bean id="nc" class="cn.tedu.domain.DBUtils" init-method="init" destroy-method="destroy"></bean>

NetConn.java

public class NetConn { //实现连接好网络后查询数据的功能
    public void init(){System.out.println("连接数据库...");}
    public void sendData(){
        System.out.println("发送数据...");
    }
    public void destroy(){System.out.println("断开数据库连接..");}
}

TestDemo.java

@Test
public void test04(){
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    NetConn nc = (NetConn)context.getBean("nc");
    nc.sendData();
    ((ClassPathXmlApplicationContext)context).close();
}

spring框架源码 spring框架入门教程_创建对象_12