Spring(1)

1.Spring简介

spring是一个轻量级的JavaEE应用框架。
对比EJB(Enterprise Java Beans)技术是官方制定的重量级的JavaEE解决方案。
EJB问题:

  1. 开发调试麻烦
  2. 和ejb容器耦合,不利于后期的维护
    Spring构建于众多优秀的设计模式之上,比如:工厂设计模式代理设计模式、模板方法设计模式、策略设计模式…。

设计模式:前人总结的,用于解决特定问题的优秀的方案。

学习Spring,本质上就是在学这些设计模式解决了哪些问题?

2.工厂设计模式

工厂设计模式:使用工厂类创建对象,替换传统的new创建对象。
new创建对象的问题:

class UserAction{
	public String execute(){
		//调用业务层方法
		UserServrice service = new UserServiceImpl();
	}
}
/**
* 从设计角度分析
* 1.UserAction直接依赖于UserServiceImpl,强耦合
* 2.如果要替换UserServiceImpl,那么必须修改源码,影响程序的可维护性和扩展性

new模式下:类和类之间是强耦合,如果要扩展程序,必须要修改源码,违背开闭原则。

解决方案:工厂模式(解耦合)
下面是简略代码

//Action层
class UserAction{
	public String execute(){
		//调用业务层方法
		UserServrice service = BeanFactory.getBean("UserServrice");
	}
}
//工厂类BeanFactory
class BeanFactory {
	//通过流读取配置文件,获取id和全类名的对应关系
	InputStream in = BeanFactory.class.getResourceAsStream("/applicationContext.properties"
	prop.load(in);
	//通过反射创建对象
    Class c = Class.forName(prop.getProperty(id));
    return c.newInstance();
}
//配置文件(applicationContext.properties)
<!--    <bean id="唯一标识" class="全类名"/>-->
<bean id="xxxService2" class="com.jinshida.service.impl.UserServiceImpl"/>

具体步骤:
1.创建一个工厂类BeanFactory+配置文件(applicationContext.properties)
2.将new替换为工厂创建对象
3.面向接口编程(定义接口类型的引用)
工厂模式特点:配置文件+反射+面向接口编程
好处:解耦合

3.第一个Spring程序

Spring框架最基本的使用:对象工厂(容器)。通过Spring工厂创建对象,解耦合从而提高程序的可维护性和扩展性。

3.1 Spring工厂的使用步骤

  1. 搭建开发环境

    1. 新建项目
    2. 导入依赖
    <!-- 引入spring依赖-->
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>5.2.6.RELEASE</version>
        </dependency>
    
    1. 导入配置文件
      建议resources根目录下建立applicationContext.xml

2.编码+配置
配置:在applicationContext.xml中配置要创建哪些对象

<bean id="唯一标识" class="全类名"/>
<!-- new UserServiceImpl1() -->
<bean id="userService" class="com.jinshida.service.impl.UserServiceImpl"/>

编码:从Spring工厂中获取对象

BeanFactoryApplicationContext 工厂类型(接口)

/**
*实现类:ClassPathXmlApplicationContext (非web环境)
*​        XmlWebApplicationContext (Web环境)
*方法  :Object getBean(String id)
*/
//创建Spring工厂
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

//从工厂中获取对象
UserService userService = (UserService) context.getBean("userService");
userService.removeUser(1);

示例:BeanFactory.java

public class BeanFactory {
    private static Properties prop = new Properties();
    static {
        InputStream in = BeanFactory.class.getResourceAsStream("/applicationContext.properties");
        try {
            prop.load(in);
            in.close();
        }catch(IOException e){
            e.printStackTrace();
            throw new RuntimeException(e);
        }

    }
    //用于创建对象
    public static Object getBean(String id){
        //通过流读取配置文件,获取id和全类名的对应关系
        try {

            //通过反射创建对象
            Class c = Class.forName(prop.getProperty(id));
            return c.newInstance();
        }catch(Exception e){
            e.printStackTrace();
            throw new RuntimeException(e);
        }
    }
}

4 Spring框架的模块一览

Spring框架模块

  1. Test:简化Spring项目的测试
  2. 核心容器:Spring作为工厂的实现
  3. AOP:面向切面编程,是面向对象编程有利的补充,可以非侵入的为代码添加额外功能。
  4. 辅助功能
  5. Data Access:提供数据库访问
  6. Web:Spring对JavaWeb开发的支持

Spring族系的框架种类丰富:SpringMVC、SpringData、SpringTask、SpringSecurity、SpringBoot、SpringCloud…。除此之外,Spring框架可以轻松的和其它框架整合,调度其它框架。

5 Spring工厂的实现原理

Spring工厂创建对象:读取配置文件(applicationContext.xml)中的信息,获取class属性配置的全类名,通过反射,默认调用类的无参构造方法创建对象。

bean标签的scope属性控制创建的对象是否是单例的。

​ scope 属性值

​ singleton(默认值)单例 Spring在工厂创建时随即创建对象

​ prototype 多例 Spring工厂默认不主动创建,直到getBean时创建

Spring工厂创建对象为什么默认单例?节省内存资源。

可以被用户共用(单例):dao 、service、 sqlSessionFactory

不可以被用户公用(多例):connection、sqlSession、ShoppingCart、Action

6 注入(Injection)- -赋值

由Spring工厂为对象的属性赋值(注入值)。

6.1 Set注入

本质:通过无参构造方法创建对象后,调用属性的set方法赋值。
前提:类中必须有无参构造方法,属性必须提供set方法。
操作:在bean标签中,定义property子标签给属性赋值。

6.1.1 基本类型(包装类)+String
用法:
<property name="属性名">
    <value>基本类型或String数据</value>
</property>
或:
<property name="属性名" value="基本类型或String数据"/>
示例:
<bean id="s1" class="com.jinshida.entity.Student" scope="prototype">
        <!--<property name="id">
            <value>1</value>
        </property>
        <property name="name">
            <value>xiaohei</value>
        </property>
        <property name="sex">
            <value>true</value>
        </property>
        <property name="score">
            <value>100.0</value>
        </property>-->
        <property name="id" value="1"/>
        <property name="name" value="xiaohei"/>
        <property name="sex" value="true"/>
        <property name="score" value="100.0"/>
    </bean>
6.1.2 自定义类型
用法:
<property name="属性名">
	<ref bean="另外一个Bean的id属性"/>
</property>

<property name="属性名" ref="另外一个Bean的id属性"/>

示例:
 <bean id="addr" class="com.jinshida.entity.Address" scope="prototype">
     <property name="city" value="郑州"/>
     <property name="street" value="文化路"/>
</bean>

<bean id="p" class="com.jinshida.entity.Person">
    <property name="id" value="1"/>
    <property name="name" value="xiaohei"/>
    <!--<property name="address">
            <ref bean="addr"/>
        </property>-->
    <property name="address" ref="addr"/>
</bean>
6.1.3 数组、List、Set类型
用法:
<property name="数组属性名">
	<array>
    	<value>基本类型或者String</value>
        <ref bean="另外一个bean的id"/>
        ...
    </array>
</property>

<property name="数组属性名">
	<list>
    	<value>基本类型或者String</value>
        <ref bean="另外一个bean的id"/>
        ...
    </list>
</property>

<property name="数组属性名">
	<set>
    	<value>基本类型或者String</value>
        <ref bean="另外一个bean的id"/>
        ...
    </set>
</property>

示例:
<property name="os">
    <array>
        <value>1</value>
        <value>xiaohei</value>
        <value>true</value>
        <ref bean="addr"/>
    </array>
</property>

<property name="list">
    <list>
        <value>1</value>
        <value>xiaohei</value>
        <value>true</value>
        <value>1</value>
        <ref bean="addr"/>
    </list>
</property>

<property name="set">
    <set>
        <value>1</value>
        <value>xiaohei</value>
        <value>true</value>
        <value>1</value>
        <ref bean="addr"/>
    </set>
</property>

注意:array、list、set 3个标签通用,但仍建议针对性使用。
6.1.4 Map类型
用法:
<property name="map属性名">
	<map>
    	<entry key="基本类型或String的key" value="基本类型或String的value"/>
        <entry key="基本类型或String的key" value-ref="bean的id"/>
    </map>
</property>

示例:
<property name="map">
    <map>
        <!-- 一个元素,是一个键值对-->
        <entry key="name" value="xiaohei"></entry>
        <entry key="address" value-ref="addr"></entry>
      <!--<entry key-ref="bean的id" value-ref="bean的id"/>-->
    </map>
</property>
6.1.5 Properties类型
用法:
<property name="properties属性名">
	<props>
    	<prop key="键字符串">值字符串</prop>
        ...
    </props>
</property>

示例:
<property name="properties">
    <props>
        <!-- 每一个键值对都是String -->
        <prop key="name">xiaohei</prop>
        <prop key="age">18</prop>
    </props>
</property>

6.2 构造注入

本质:在调用有参构造方法创建对象时,为属性赋值。

前提:类中必须有有参构造方法。

操作:在bean标签中添加constructor-arg子标签进行配置。

6.2.1基本使用

当形参数量不同时,直接根据constructor-arg的数量进行匹配,按照constructor-arg标签的顺序给参数赋值。

public class User implements Serializable {
    private Integer id;
    private String name;
    private String password;

    public User() {
    }

    public User(Integer id) {
        this.id = id;
    }
	 public User(String name) {
        this.name = name;
    }
    public User(Integer id, String name) {
        System.out.println("id = [" + id + "], name = [" + name + "]");
        this.id = id;
        this.name = name;
    }

    public User(Integer id, String name, String password) {
        System.out.println("id = [" + id + "], name = [" + name + "], password = [" + password + "]");
        this.id = id;
        this.name = name;
        this.password = password;
    }
    ...
}


 <!--通过构造注入为属性赋值-->
<bean id="u1" class="com.jinshida.entity.User" scope="prototype">
    <!-- 调用3个参数-->
    <constructor-arg value="1" />
    <constructor-arg value="xiaohei"/>
    <constructor-arg value="123456"/>
</bean>

<bean id="u2" class="com.jinshida.entity.User" scope="prototype">
    <!--调用2个参数-->
    <constructor-arg value="1"/>
    <constructor-arg value="xiaobai"/>
</bean>
6.2.2 type属性

type属性设置参数的类型,解决构造方法数量相同类型不同的匹配难题。

public User(Integer id) {
    System.out.println("id = [" + id + "]");
    this.id = id;
}
public User(String name) {
    System.out.println("name = [" + name + "]");
    this.name = name;
}
<bean id="u3" class="com.jinshida.entity.User" scope="prototype">
    <constructor-arg value="1" type="java.lang.Integer"/>
</bean>

注意:当构造参数多个时,一旦使用type属性,constructor-arg标签的顺序和构造方法参数的顺序不再匹配。

6.2.3 index属性

index属性用于设置constructor-arg标签的参数顺序,配合type属性一起解决形参数量相同、形参类型相同但顺序不同的匹配难题。

public User(Integer id, String name) {
    System.out.println("id = [" + id + "], name = [" + name + "]");
    this.id = id;
    this.name = name;
}

public User(String name,Integer id) {
    System.out.println("name = [" + name + "], id = [" + id + "]");
    this.id = id;
    this.name = name;
}
<bean id="u2" class="com.jinshida.entity.User" scope="prototype">
    <constructor-arg value="1" type="java.lang.Integer" index="0"/>
    <constructor-arg value="2" type="java.lang.String" index="1"/>
</bean>

6.3 自动装配

本质:由Spring自动分析Bean的依赖,底层自动调用对象属性的set方法或者调用构造方法进行赋值。

操作:通过bean标签的属性 autowire =“byName|byType|constructor”.

<bean id="userService" class="com.jinshida.service.impl.UserServiceImpl" />

    <!-- 
        autowire="byName" Spring根据userAction的属性名从Sprnig工厂中获取bean
		autowire="byType" Spring根据userAction的属性类型自动从Spring工厂中获取所需的属性,Spring不能有多个相同类型的对象
		autowire="constructor" 类似于byType,但是是分析构造方法的参数类型,底层调用构造方法完成注入。如果找不到匹配的参数,将抛出异常
    -->
<bean id="userAction" class="com.jinshida.action.UserAction" autowire="byName"/>  

注意:实战中,Spring工厂不管理实体对象的创建,(实体对象的创建仍由MyBatis这类dao层框架负责处理)。

Spring工厂主要负责 dao、service、action

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值