栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

Java - Spring 框架 SpringFramework 详解(二)

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java - Spring 框架 SpringFramework 详解(二)

目录
      • 1. Spring IoC
        • 1.1. 什么是IoC
        • 1.2. 通过SET方式注入属性的值
        • 1.3. 通过构造方法注入属性的值【不常用】
      • 2. 注入集合类型的值
        • 2.1. 注入List类型的值【不常用】
        • 2.2. 注入SET集合类型的属性值【不常用】
        • 2.3. 注入数组类型的属性值【不常用】
        • 2.4. 注入Map集合类型的属性值【不常用】
        • 2.5. 使用系列节点【不常用】
        • 2.6. 注入Properties类型的属性值【常用】
      • 3. Spring表达式
      • 附1:什么时候需要定义构造方法
      • 附2:关于集合的类型

1. Spring IoC 1.1. 什么是IoC

Spring IoC表示控制反转,即在传统模式下,是由程序员编写代码创建并管理对象,例如User user = new User();,当使用Spring框架之后,则将对象的创建、管理的“权力”交给了框架,则表示控制权是给了框架,所以,称之为控制反转!

Spring框架是通过DI(做法、手段)实现了IoC(效果、目标),DI(Dependency Injection)表示依赖注入。

1.2. 通过SET方式注入属性的值

在对象的运行过程中,需要使用另一个对象,在编写代码时,在一个类中需要声明另一个类的对象,则表现出了依赖关系!例如在UserLoginServlet中声明了UserDao类型的属性,则称之为UserLoginServlet依赖于UserDao。

使用Spring框架,不仅可以管理某个类的对象,还可以在创建对象的同时,为该类中声明的属性进行赋值,这种赋值操作就称之为注入。

假设存在:

public class User {
	public String name;
}

希望通过Spring获取该User类的对象时,对象的name属性已经有值!首先,需要为name属性添加规范的SET方法:

public void setName(String name) {
	this.name = name;
}

然后,在Spring的配置文件中,为配置User类的节点添加子级的节点:



练习:在User类中添加Integer age属性,表示年龄,添加String from属性,表示来自哪里,为这2个属性注入值!

注意:在配置节点时,name属性的值,其实,并不是类中的属性名,而是类中的方法名调整后的属性名,即将方法名称左侧的set去掉,将字母改为小写后名称!或者说,在Spring框架工作时,会根据配置的中的name值,将首字母大写,并在左侧拼接上set,形成方法名,并调用该方法!

另外,可能还有一些类中的属性,并不是可以直接写出来的直接值,例如存在UserLoginServlet,其中有UserDao属性,如果需要为这个属性注入值,就需要使用ref属性引用另一个Bean:


	

	
	

在注入属性值时,value和ref都表示“值”,其中value用于可以直接写出来的值,例如字符串类型的值、数值、布尔值,而ref用于引用另一个Bean,当使用ref属性时,取值为另一个节点的id。

1.3. 通过构造方法注入属性的值【不常用】

假设存在:

public class Person {
	public String from;
}

如果需要为以上from属性注入值,并且不使用SET方式来注入,则可以先添加带参数的构造方法,在构造方法中,为from属性赋值:

public class Person {
	public String from;

	public Person(String from) {
		super();
		this.from = from;
	}
}

在Spring的配置文件中:


	
	
	

以上使用的节点就是用于配置构造方法的参数的,如果构造方法中有多个参数,则需要多个该节点,每个节点配置1个参数!在该节点的index表示配置第几个参数,取值从0开始顺序编号!至于参数的值的配置,依然需要根据值的类型选择使用value或ref来配置!

练习:假设存在Student类,类中有String name、Integer age、Date createdTime这3个属性,请通过构造方法注入值的方式,为这3个属性注入值!

答案:关于Student类:

public class Student {
	
	public String name;
	public Integer age;
	public Date createdTime;
	
	public Student(String name, Integer age, Date createdTime) {
		super();
		this.name = name;
		this.age = age;
		this.createdTime = createdTime;
	}

	@Override
	public String toString() {
		return "Student [name=" + name + ", age=" + age + ", createdTime=" + createdTime + "]";
	}
	
}

答案:关于Spring配置:




	
	
	

2. 注入集合类型的值 2.1. 注入List类型的值【不常用】

假设存在SampleBean的类,在类中有List names属性,用于存储多个用户的名称,需要为该集合类型的属性注入值!

首先,需要为该属性添加SET方法:

public class SampleBean {
		
	// Lucy, Jack, Kate, Tom
	public List names;

	public void setNames(List names) {
		this.names = names;
	}

}

在配置时,由于使用的是SET方式注入,所以,依赖在节点下添加子级的节点,只不过这次在中只配置name属性,并不配置value或ref属性,而是在子级添加节点,并在的子级添加若干个节点以配置若干个值:


	
		
			Lucy
			Jack
			Kate
			Tom
		
	

2.2. 注入SET集合类型的属性值【不常用】

假设在以上类中存在Set集合类型的属性,并需要注入值:

// Beijing, Shanghai, Guangzhou, Shenzhen
public Set cities;

先在类中添加该属性对应的SET方法:

public void setCities(Set cities) {
	this.cities = cities;
}

然后,在Spring配置文件中添加配置:


	
		Beijing
		Shanghai
		Guangzhou
		Shenzhen
	

在Spring框架中处理Set类型的数据时,使用的是linkedHashSet,这种Set是使用链表的结构存储数据的,所以,查询出来的数据的顺序与添加时是保持一致的!

2.3. 注入数组类型的属性值【不常用】

假设在以上类中存在数组类型的属性,并需要注入值:

// JavaOOP, JavaSE, MySQL, JDBC
public String[] skills;

先在类中添加该属性对应的SET方法:

public void setSkills(String[] skills) {
	this.skills = skills;
}

然后,在Spring配置文件中添加配置:


	
		JavaOOP
		JavaSE
		MySQL
		JDBC
	

在配置集合类型的属性时,配置List集合类型的属性,与配置数组类型的属性时,使用的节点结构可以随意,即:使用节点,或使用节点均可!

2.4. 注入Map集合类型的属性值【不常用】

假设在以上类中存在Map类型的属性,并需要注入值:

// username=Billy, age=23, password=javaee
public Map session;

先在类中添加该属性对应的SET方法:

public void setSession(Map session) {
	this.session = session;
}

然后,在Spring配置文件中添加配置:


	
		
		
		
	

2.5. 使用util:xx系列节点【不常用】

假设在以上类中存在List集合类型的属性,并需要注入值:

// Eclipse, MySQL, Office, Intellij IDEA
public List tools;

先在类中添加该属性对应的SET方法:

public void setTools(List tools) {
	this.tools = tools;
}

然后,在Spring配置文件中,先添加一个与节点同级别的节点:


	Eclipse
	MySQL
	Office
	Intellij IDEA

然后,需要注入属性值时,通过ref引用到以上配置的节点即可:


使用这种做法的配置可以将一部分代码从原本的的子级分离出来,虽然可能不太直观,但是,在代码篇幅较长的情况下,可以利于管理代码,另外,使用这种做法还可以将配置的集合的值进行复用(重复使用)!

另外,还有节点可以配置Set集合和Map集合的值!

2.6. 注入Properties类型的属性值【常用】

假设在src/main/resources存在jdbc.properties文件,文件中有如下配置:

url=jdbc:mysql://localhost:3306/database?useUnicode=true&characterEncoding=utf-8
driver=com.mysql.jdbc.Driver
username=root
password=123456

需要将这些配置读取到程序中,则需要在类中声明Properties类型的属性:

// 值来自src/main/resources/jdbc.properties
public Properties jdbcConfig;

要使用SET方式注入值,还是添加SET方法:

public void setJdbcConfig(Properties jdbcConfig) {
	this.jdbcConfig = jdbcConfig;
}

在Spring的配置文件中,首先,使用节点读取以上jdbc.properties配置文件:




然后,在类的节点子级,添加节点注入属性的值:


当然,也可以不使用.properties文件,而是直接将各属性的配置直接注入到节点的下级,例如:


	
		administrator
		12345678
	

通常,还是推荐将这类配置写在.properties文件中,而不推荐以上做法!

3. Spring表达式

在配置Spring的配置文件时,可以通过Spring表达式实现获取另一个bean的某个属性值。

假设存在ValueBean类,其中的String name属性的值需要来自User类中的name属性,如果使用SET方式为ValueBean的name属性注入值,首先,还是要添加对应的SET方法:

public class ValueBean {
		
	// 值:User类的对象中的name属性值
	public String name;

	public void setName(String name) {
		this.name = name;
	}

}

然后,在Spring的配置文件中进行配置:


	

Spring表达式的基本格式是使用#{}格式的占位符,需要使用value属性进行配置!

如果值来自另一个bean的属性,则Spring表达式的格式是:

#{bean-id.属性名}

当然,值也可以是另一个bean的List集合中的某个元素,例如:

// 值:SampleBean的names中的第3个值
public String username;

则注入值时的配置为:


所以,如果要获取另一个bean中的List集合中的某个元素,Spring表达式的格式是:

#{bean-id.属性名[索引]}

由于在Spring中注入值时,Set集合的实现类是linkedHashSet,是以链表的形式存储数据的,所以,也可以取出这种集合中的第x个元素,取值方式与从List集合中取出某个的值的做法完全相同!

另外,还可以获取某个Map类型的属性中的值,例如:

// 值:SampleBean的session的password
public String password;

则配置为:


所以,获取Map中的值的Spring表达式的格式为:

#{bean-id.Map类型的属性名.Key}

另外,还可以写成:

#{bean-id.Map类型的属性名['Key']}

通过以上方式,还可以获取Properties类型的属性的某个值!

附:
单元测试代码:

package cn.tedu.spring;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.Arrays;

public class TestGetBean {
    private ClassPathXmlApplicationContext ac;
    @Before
    public void onBefore () {
        // 加载spring 配置文件,获取spring容器
        ac = new ClassPathXmlApplicationContext("spring.xml");
    }

    @Test
    public void testGetBean () {
        // 通过spring 容器获取对象
        User user = (User) ac.getBean("user");
        // 测试
        System.out.println("user => " + user);
        System.out.println("user => name = " + user.name);
        System.out.println("user => age = " + user.age);
    }

    @Test
    public void testUserLoginServlet () {
        // 通过spring 容器获取对象
        UserLoginServlet userLoginServlet = (UserLoginServlet) ac.getBean("userLoginServlet");

        // 测试
        System.out.println("userLoginServlet => " + userLoginServlet);
        System.out.println("userLoginServlet => userDao = " + userLoginServlet.userDao);
    }

    @Test
    public void testPerson () {
        // 通过spring 容器获取对象
        Person person = ac.getBean("person", Person.class);
        // 测试
        System.out.println("person => " + person);
        System.out.println("person => from = " + person.from);
    }

    @Test
    public void testStudent () {
        // 通过spring 容器获取对象
        Student student = ac.getBean("student", Student.class);
        // 测试
        System.out.println("student => " + student);
        System.out.println("student => name = " + student.name);
        System.out.println("student => age = " + student.age);
        System.out.println("student => createdTime = " + student.createdTime);
    }

    @Test
    public void testSamleBean () {
        // 通过spring 容器获取对象
        SampleBean sampleBean = ac.getBean("sampleBean", SampleBean.class);
        // 测试
        System.out.println("sampleBean => " + sampleBean);
        System.out.println("sampleBean.names => " + sampleBean.names);
        System.out.println(sampleBean.names.getClass());
        System.out.println("sampleBean.cities => " + sampleBean.cities);
        System.out.println(sampleBean.cities.getClass());
        System.out.println("sampleBean.skills => " + Arrays.toString(sampleBean.skills));
        System.out.println("sampleBean.session => " + sampleBean.session);
        System.out.println("sampleBean.tools => " + sampleBean.tools);
        System.out.println("sampleBean.jdbcConfig => " + sampleBean.jdbcConfig);
        System.out.println("url => " + sampleBean.jdbcConfig.get("url"));
        System.out.println("driver => " + sampleBean.jdbcConfig.get("driver"));
        System.out.println("username => " + sampleBean.jdbcConfig.get("username"));
        System.out.println("password => " + sampleBean.jdbcConfig.get("password"));
    }

    @Test
    public void testValueBean () {
        // 通过spring 容器获取对象
        ValueBean valueBean = ac.getBean("valueBean", ValueBean.class);
        // 测试
        System.out.println("valueBean.name => " + valueBean.name);
        System.out.println("valueBean.username => " + valueBean.username);
        System.out.println("valueBean.city => " + valueBean.city);
    }

    @After
    public void onAfter () {
        // 释放资源
        ac.close();
    }
}

附1:什么时候需要定义构造方法

通常,如果需要自定义构造方法,可能是因为:

  1. 创建对象的同时,快速的为属性赋值;

  2. 限制对象的创建过程,例如在单例模式的设计中,将构造方法声明为私有权限;

  3. 强制要求传入某些数据。

附2:关于集合的类型

在Collection接口的子级有List和Set这2种接口类型的集合!

List集合是序列的,存入到该集合中的元素是可重复的!

Set集合是散列的,存入到该集合中的元素是不可重复的,是否重复的判断标准是:2个对象的equals()对比结果为true,且hashCode()的返回值相同,则视为同1个数据!

另外,还在Map类型的集合,是用于存储键值对的集合,即在集合中的每个数据都是有Key和Value的,并且,Key的特征与Set集合中存储数据的方式相同!

如果这篇文章有帮助到您,请简单给个赞吧,谢谢~

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/315276.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号