萤火小屋

优律的知识库

  • 首页
  • 归档
  • 分类
  • 标签
  • 留言
  • 关于

  • 搜索
消息队列 RabbitMQ Redis 双指针 力扣 动态代理 Git YAML SpringBoot SpringMVC 回溯算法 分治算法 归并排序 快排 手撕 事务 MySQL索引 MySQL 小技巧 Spring Framework Spring 动态规划 Linux Android 贪心算法 操作系统 进程调度模拟 IPv6 数据库 计算机组成原理 计算机基础 栈 Java 静态路由 路由器 交换机 数字通信 网络工程 计算机网络 Web http 大学学习技巧 程序设计 算法

Spring学习笔记-IOC

发表于 2021-02-24 | 分类于 Spring | 0 | 阅读次数 348

1 Spring概述

1.1 Spring简介

Spring实际上是一个企业级开发的免费开源的Java框架,用来简化java开发的。总之:spring是一个基于IOC和Aop的容器框架。

Spring框架的官网:https://spring.io/projects/spring-framework 点击访问

spring-framework-advantage

1.2 Spring三层架构

层表示层→→业务逻辑层→→持久化层
具体名称web层(控制层)service层dao层
作用接收、处理并响应请求处理业务逻辑和数据库相连接
模块SpringMVC声明式事务JDBCTemplate

注意:Spring Framework跨三层,不属于任意一层。SpringMVC其实是Spring Framework中的一个模块,但在开发中会被当做一个单独的框架。

分层的目的:解耦合

1.3 Spring两大部分

  1. IOC(控制反转)
    • 具体实现:DI
      1. XML
      2. 注解
  2. AOP(面向切面编程)
    • 具体实现:
      1. XML
      2. 注解

1.4 Spring Framework的模块划分


spring-framework-module-division

模块说明
spring-famework-module-description

1.5 Spring Framework的jar包

  1. Spring开发必须添加的jar包

    spring-beans-4.0.0.RELEASE.jar
    spring-context-4.0.0.RELEASE.jar
    spring-core-4.0.0.RELEASE.jar
    spring-expression-4.0.0.RELEASE.jar
    以上四种是Spring中的核心容器包

    commons-logging-1.1.3.jar 是上边四个的依赖

  2. 每个jar包不同的版本

    用core核心包来举例

spring-core-4.0.0.RELEASE.jarspring-core-4.0.0.RELEASE-javadoc.jarspring-core-4.0.0.RELEASE-sources.jar
这种类型jar包是字节码文件(后缀名为class)打成的jar包,开发中可以直接用这种类型是注释生成的jar包,其中有很多帮助文档。这种jar包是源码(后缀名为java)打成的jar包,开发中不使用,只在看源码的时候会用

注:以上均用4.0.0版本举例。

2 控制反转(IOC)

2.1 IOC简介

IOC全称:Inverse Of Control,即控制反转。

定义:是指的将对象的创建和对象关联关系的维护由原来我们自己创建,自己维护对象之间的关联关系,反转给了spring的容器来创建对象和维护对象之间的关联关系。

作用: 实现了上层模块对下层模块的控制,摆脱了上层模块严重依赖下层模块的问题。

常规思想:上层模块→→→→(依赖)→→→→下层模块
IOC思想 :上层模块→→→→(注入)→→→→下层模块

IOC的底层实现:XML解析技术+反射+设计模式+容器

2.2 获取容器对象的三种方式

  1. 在类路径下寻找配置文件来实例化容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");  //使用applicationContext加载spring容器

ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"com/test/ac/beans.xml"});  //如果定义成数组一次可以加载多个spring容器

// 使用context.getBean(Object.class);可以获取容器中的类对象
  1. 在文件系统路径下寻找配置文件来实例化容器
ApplicationContext context = new FileSystemXmlApplicationContext("D:\\TestSpring\\SpringBean\\src\\com\\test\\ac\\beans.xml");
  1. 使用BeanFactory(已过时,不推荐使用)
BeanFactory factory = new XmlBeanFactory(new FileSystemResource("D:\\TestSpring\\SpringBean\\src\\com\\test\\ac\\beans.xml"));
  • 方法总结

Three-ways-to-get-spring-container

2.3 从容器中获取bean对象的两种方式

  1. 通过字节码方式
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

Test01 t1 = context.getBean(Test01.class);
  1. 通过容器中bean标签的id值来获取

在applicationContext.xml文件中的<bean>标签中有一个属性为id,该属性可设置为任意唯一值,用来标识该bean

<bean id="test1" class="com.test1.Test01"></bean>
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

Object t1 = context.getBean("test1");  // 注意返回类型为Object

2.4容器中的bean对象创建原理

  1. 创建时机:默认为加载容器的时候
  2. 底层原理:反射
  3. 是否单例:默认为单例
  • 修改其创建时机和是否单例
    需要在bean标签中设置scope属性
<bean id="test1" class="com.test1.Test01" scope="singleton"></bean>

scope有四个值

requestsessionsingletonprototype
表示每一个request请求创建一个对象表示每一个session会话创建一个对象scope的默认值,表示该对象在容器加载的时候创建且单例表示该对象在从容器中获取bean对象的时候才创建且多例


2.5依赖注入(DI)

2.5.1 DI简介

英文全称Dependency Injection,简称DI。IOC是一种思想,DI是IOC的具体实现。

有了依赖注入,不再需要自己手动为变量赋值

2.5.2 举个例子

<!--applicationContext.xml文件部分代码-->

<bean id="userDao" class="com.test.dao.UserDao"></bean>

<bean id="userservice" class="com.test.service.UserService">
	<property name="userDao" ref="userDao"></property>
</bean>
// UserDao.java文件部分代码

package com.test.dao

public class UserDao{
	public void testSuccess(){
		System.out.println("success");
	}
}
// UserService.java文件部分代码

package com.test.service

public class UserService{
	private UserDao userDao;
	public void setUserDao(UserDao userDao){
		this.userDao = userDao;
	}
	public UserDao getUserDao(){
		return userDao;
	}
}

2.6 分模块配置和import标签

由于Spring框架现在是一个生态,会整合很多个其它框架,如果我们把Spring整合其它框架的配置信息都配置在Spring的配置文件里面,势必会导致Spring的配置文件过于臃肿,维护起来非常不方便,所以一般会把Spring整合其它框架的配置信息提取出来,放在一个单独的文件里,然后在Spring的配置文件中通过import标签引入整合的配置信息即可。

  • 举例
    假如我们有一个邮件模块的配置文件applicationContext-email.xml其中配置了e-mail的模块配置,如将其“拼接”到applicationContext.xml中,可进行如下写法
<!-- 在想引入邮件配置的位置加入语句 -->
<import resource="classpath:applicationContext-email.xml" />

2.7 内部bean和外部bean

  1. 外部bean:在<beans>标签内部直接定义的bean对象叫外部bean,外部bean可以被多次引用。
  2. 内部bean:在某个<bean>标签内部定义的bean对象叫内部bean,内部bean只能被某个对象的某个属性引用。

内部bean代码例子

<!-- applicationContext.xml文件部分内容 -->

<bean id="userServiceInside" class="com.tech.service.UserService">
	<property name="userDao">  <!-- 在property标签内部进行赋值 -->
		<bean class="com.tech.dao.UserDao"></bean>
	</property>
</bean>

2.8 容器创建对象的三种方式

  1. 构造器
    一般情况下使用的方法,例子如下
// 测试类中的测试方法(部分)
@Test
public void test01(){
		
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
	UserService userService = (UserService)context.getBean("userService");
		
}
// UserService类(部分)
public class UserService {

	private UserDao userDao;
		
	public UserService(){
		System.out.println("UserService通过无参构造器实例化");  
		// 在无参构造器中添加一段话,执行测试方法后看看控制台
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
	
}
<!-- applicationContext.xml部分内容 -->

<bean id="userDao" class="com.tech.dao.UserDao"></bean>

<bean id="userService" class="com.tech.service.UserService">
	<property name="userDao" ref="userDao"></property>
</bean>

Create-object-in-container-constructor-create-example-console-display

  1. 静态工厂
    通过类得静态方法得到的bean对象,下边举例
// 创建一个静态工厂类(展示部分代码)
public class StaticFactory {

	public static UserService getUserService(){
		
		UserService userService = new UserService();
		UserDao userDao = new UserDao();
		
		userService.setUserDao(userDao);
		
		return userService;
	}
	
}
// UserService.java部分代码
public class UserService {

	private UserDao userDao;
		
	public UserService(){
		System.out.println("UserService无参构造器运行成功");
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
	
}
// UserDao.java部分代码
public class UserDao {

	public UserDao(){
		System.out.println("UserDao无参构造器运行成功");
	}
	
}
<!-- applicationContext.xml部分代码 -->
<bean id="userServiceByStaticFactory" class="com.tech.factory.StaticFactory" factory-method="getUserService"></bean>
<!-- 
     解释一下:
     class的值是静态工厂的类全路径名,
     factory-method字段的值是静态工厂的静态方法,这个静态方法一定要返回一个该bean对应的实例值
-->
// 测试类执行方法代码
@Test
public void test02(){
		
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
	UserService userService = (UserService)context.getBean("userServiceByStaticFactory");
		
}

控制台打印

Create-object-in-container-static-factory-create-example-console-display

  1. 实例工厂
    调用一个对象的普通方法返回的一个对象,这里用的UserDao类和UserService类同上一样,不再重写
// InstanceFactory.java部分代码
public class InstanceFactory {

	public UserService getUserService(){
		// 该方法内容和上一个静态工厂方法一样(换汤不换药)
		UserService userService = new UserService();
		UserDao userDao = new UserDao();
		
		userService.setUserDao(userDao);
		
		return userService;
	}
	
}
<!-- applicationContext.xml部分代码 -->

<!-- 首先将InstanceFactory实例化成bean -->
<bean id="instanceFactory" class="com.tech.factory.InstanceFactory"></bean>
	 
<!-- 再通过id为instanceFactory的bean的getUserService方法创造id为userServiceByInstanceFactory的bean -->
<bean id="userServiceByInstanceFactory" factory-bean="instanceFactory" factory-method="getUserService"></bean>
// 测试方法部分代码
@Test
public void test03(){
		
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
	UserService userService = (UserService)context.getBean("userServiceByInstanceFactory");

}

结果打印

Create-object-instance-in-container-factory create-instance-console-display

2.9 属性赋值

2.9.1 按属性类型划分

  1. 值注入
    基本数据类型及其对应的包装类,例如:Integer。String类型也在其中。

  2. 引用注入
    数据是引用类型

举例:

<!-- applicationContext.xml部分代码 -->
<bean id="userDao" class="com.tech.dao.UserDao">
	<property name="udid" value="1002" />  <!-- 这是值注入 要用关键字value -->
</bean> 
<bean id="userService" class="com.tech.service.UserService"> 
	<property name="usid" value="1001" />  <!-- 这是值注入 要用关键字value -->
	<property name="userDao" ref="userDao" />  <!-- 这是引用注入 要用关键字ref -->
</bean> 
// UserService.java全部代码

package com.tech.service;

import com.tech.dao.UserDao;

public class UserService {

	private String usid;
	private UserDao userDao;
	
	public UserService() {}

	public String getUsid() {
		return usid;
	}

	public void setUsid(String usid) {
		this.usid = usid;
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
	
	@Override
	public String toString() {  // 重写toString方法 使其打印在控制台上的时候能够看到属性的值
		return "UserService [usid=" + usid + ", userDao=" + userDao + "]";
	}

}
// UserDao.java全部代码

package com.tech.dao;

public class UserDao {
	
	private String udid;
	
	public UserDao(){}

	public String getUdid() {
		return udid;
	}

	public void setUdid(String udid) {
		this.udid = udid;
	}
	
	@Override
	public String toString() {  // 重写toString方法 使其打印在控制台上的时候能够看到属性的值
		return "UserDao [udid=" + udid + "]";
	}
	
}

// 测试方法

@Test
public void test03(){
		
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
	UserService userService = (UserService)context.getBean("userService");
		
	System.out.println(userService);
}

控制台打印
Bean property assignment is divided by property type

2.9.2 注入方式划分

2.9.2.1 构造器注入

通过<constructor-arg></constructor-arg>标签实现

举例:

<!-- applicationContext.xml部分代码 -->
<bean id="userDaoByConstructor" class="com.tech.dao.UserDao">
	<constructor-arg name="udid" value="1003" />
</bean>
// UserDao.java全部代码
package com.tech.dao;

public class UserDao {
	
	private String udid;
	
	public UserDao(){}  // 提供一个无参构造器(好习惯)

	public UserDao(String udid) {  // 一定要提供一个有参构造器
		this.udid = udid;
	}

	public String getUdid() {
		return udid;
	}

	public void setUdid(String udid) {
		this.udid = udid;
	}

	@Override
	public String toString() {  // 重写toString方法
		return "UserDao [udid=" + udid + "]";
	}
}
// 测试方法
@Test
public void test04(){
		
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
	UserDao userDao = (UserDao)context.getBean("userDaoByConstructor");
		
	System.out.println(userDao);
}

控制台打印结果
Attribute assignment is classified by injection method, and constructor injection is used

注意:当类有两个或多个仅仅是参数顺序不一致的构造器的时候,程序默认总是选择最后一个。例子如下。

// UserService.java全部代码
package com.tech.service;

import com.tech.dao.UserDao;

public class UserService {

	private String usid;
	private UserDao userDao;
	
	public UserService() {}

	public UserService(String usid, UserDao userDao) {
		this.usid = usid;
		this.userDao = userDao;
		System.out.println("first constructor");
	}
	
	public UserService(UserDao userDao, String usid) {
		this.usid = usid;
		this.userDao = userDao;
		System.out.println("second constructor");
	}

	public String getUsid() {
		return usid;
	}

	public void setUsid(String usid) {
		this.usid = usid;
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
	}
	
	@Override
	public String toString() {
		return "UserService [usid=" + usid + ", userDao=" + userDao + "]";
	}
}
<!-- applicationContext.xml部分代码 -->
<bean id="userServiceByConstructor" class="com.tech.service.UserService">
	<constructor-arg name="usid" value="1003" />
	<constructor-arg name="userDao" ref="userDaoByConstructor" />
</bean>
@Test
public void test05(){
		
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
	UserService userService = (UserService)context.getBean("userServiceByConstructor");
		
	System.out.println(userService);
}

控制台打印信息
The property assignment is divided by the injection method. When the constructor assigns multiple constructors, the printing situation is displayed

那么该如何手动选择使用的构造器呢?答案是,在<constructor>标签中加入index参数,参数值是从0开始的正整数,0代表使用第一个构造器,依次类推。

<!-- applicationContext.xml部分代码 -->
<bean id="userServiceByConstructor" class="com.tech.service.UserService">
	<constructor-arg index="0" name="usid" value="1003" />  <!-- 这个index参数不用加在所有的标签中,只需加一个就好 -->
	<constructor-arg name="userDao" ref="userDaoByConstructor" />
</bean>

再次打印看看
The attribute assignment is divided according to the injection mode. When the constructor assigns multiple constructors, it prints the situation after adding the index parameter

如我们所愿,这次选择了第一个构造器来赋值。
另外,在<constructor>标签中还有一个参数名为type,它的参数值为该变量的类型,如果我们要指定一个变量为某个类型,那程序会自动寻找有该类型的构造器。例子如下

// UserService.java的所有构造器代码
	public UserService(String usid, UserDao userDao) {
		this.usid = usid;
		this.userDao = userDao;
		System.out.println("first constructor");
	}
	
	public UserService(UserDao userDao, String usid) {
		this.usid = usid;
		this.userDao = userDao;
		System.out.println("second constructor");
	}
	
	public UserService(UserDao userDao, Integer usid) {
		this.usid = usid.intValue() + "";  // 在这里故意加入一个Ingeger类型的usid,然后给它转换成String类型
		this.userDao = userDao;
		System.out.println("third constructor");
	}
<!-- applicationContext.xml的部分代码 -->
<bean id="userServiceByConstructor" class="com.tech.service.UserService">
	<constructor-arg type="Integer" name="usid" value="1003" />  <!-- 这里指定usid的类型为Integer,这样程序自动调用参数带有Integer类型usid参数的构造器 -->
	<constructor-arg name="userDao" ref="userDaoByConstructor" />
</bean>

打印结果
Attribute assignment is divided according to the injection mode. When the constructor assigns multiple constructors, the usage of the type parameter is printed

综上<constructor-arg>参数汇总

参数namevaluerefindextype
解释参数的名字参数的值,仅在参数为非引用类型时使用引用值,仅在参数为引用类型时使用,即该参数是个bean指定使用构造器的索引,从0开始指定参数的类型

2.9.2.2 set方法注入

  1. property标签
    在DI简介中曾有过例子,该方法会调用类中的set方法为属性赋值。
  2. p名称空间

代码演示:

<!-- applicationContext.xml完整代码代码 -->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 注意:beans标签多了一个xmlns:p参数,这是p名字空间需要的参数 -->
	<bean id="userDaoByPname" class="com.tech.dao.UserDao" p:udid="1001"></bean>  <!-- 这里使用p:udid参数为udid赋值 -->
	<bean id="userServiceByPname" class="com.tech.service.UserService" p:usid="1002" p:userDao-ref="userDaoByPname"></bean>  <!-- 注意:如果变量为引用类型,一定要加上-ref后缀 -->
</beans>

我们在set方法中添加打印语句再次执行程序

// UserService.java完整代码
package com.tech.service;

import com.tech.dao.UserDao;

public class UserService {

	private String usid;
	private UserDao userDao;
	
	public UserService() {}

	public String getUsid() {
		return usid;
	}

	public void setUsid(String usid) {
		this.usid = usid;
		System.out.println("setUsid方法被调用");
	}

	public UserDao getUserDao() {
		return userDao;
	}

	public void setUserDao(UserDao userDao) {
		this.userDao = userDao;
		System.out.println("setUserDao方法被调用");
	}
	
	@Override
	public String toString() {
		return "UserService [usid=" + usid + ", userDao=" + userDao + "]";
	}
}

控制台打印
The property assignment is divided according to the injection mode, and the set method assignment is printed by the p-name space assignment console

2.9.2.3 注解方式注入

该方法记于该章节

2.10 复杂数据类型的赋值

当类的成员变量是诸如数组、List、Set、Map、Properties等复杂数据类型的时候,需要在<property>标签下创建对应数据类型的标签,演示代码如下,解释写在注释中。

// ComplexBean.java全部代码 
package com.tech.complexbean;

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

public class ComplexBean {
	
	private Object[] objArray;
	private List list;
	private Set set;
	private Map map;
	private Properties props;

	public Object[] getObjArray() {
		return objArray;
	}

	public void setObjArray(Object[] objArray) {
		this.objArray = objArray;
	}

	public List getList() {
		return list;
	}

	public void setList(List list) {
		this.list = list;
	}

	public Set getSet() {
		return set;
	}

	public void setSet(Set set) {
		this.set = set;
	}

	public Map getMap() {
		return map;
	}

	public void setMap(Map map) {
		this.map = map;
	}

	public Properties getProps() {
		return props;
	}

	public void setProps(Properties props) {
		this.props = props;
	}
	
}
// applicationContext.xml全部代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

	
	<bean id="userDaoByComplexBeanOutside" class="com.tech.dao.UserDao" p:udid="userDaoByComplexBeanOutside"></bean> 
	<bean id="userServiceByComplexBeanOutside" class="com.tech.service.UserService"> 
		<property name="usid" value="userServiceByComplexBeanOutside" />
		<property name="userDao" ref="userDaoByComplexBeanOutside" /> 
	</bean>
	
	<bean id="complexBean" class="com.tech.complexbean.ComplexBean">
		<property name="objArray">
			<array>                    <!-- 如果是数组类型这里要添加array标签 -->
				<value>A value in objArray</value>    <!-- 如果是普通类型变量就使用value标签 -->
				<bean id="userDaoInComplexBeanArray" class="com.tech.dao.UserDao" p:udid="userDaoInComplexBeanArray"></bean>  <!-- 还可以在array标签里写bean标签 -->
				<ref bean="userServiceByComplexBeanOutside" />  <!-- 在array标签里还可以使用ref标签直接引用已有的外部bean -->
			</array>
		</property>
		<property name="list">
			<list>                      <!-- 如果是List容器这里要添加list标签 -->
				<value>A value in list</value>  <!-- 在list中如果是普通类型变量就使用value标签 -->
				<bean id="userDaoInComplexBeanList" class="com.tech.dao.UserDao" p:udid="userDaoInComplexBeanList"></bean>  <!-- 可以在List标签里写bean标签 -->
				<ref bean="userServiceByComplexBeanOutside" />  <!-- 在list里也可以使用ref标签直接引用已有的外部bean -->
			</list>
		</property>
		<property name="set">
			<set>                       <!-- 如果是set容器这里要添加list标签 -->
				<value>A value in set</value>   <!-- 在set中如果是普通类型变量就使用value标签 -->
				<bean id="userDaoInComplexBeanSet" class="com.tech.dao.UserDao" p:udid="userDaoInComplexBeanSet"></bean>  <!-- 可以在Set标签里写bean标签 -->
				<ref bean="userServiceByComplexBeanOutside" />  <!-- 在Set里也可以使用ref标签直接引用已有的外部bean -->
			</set>
		</property>
		<property name="map">
			<map>                       <!-- 如果是Map容器这里要添加list标签 -->
				<entry key="firstKey" value="firstValue"></entry>          					   <!-- 键值均是普通数据类型 -->
				<entry key-ref="userDaoByComplexBeanOutside" value="secondValue"></entry>      <!-- 键是引用类型,值是普通数据类型 -->
				<entry key="thirdKey" value-ref="userDaoByComplexBeanOutside"></entry>         <!-- 键是普通数据类型,值是引用数据类型 -->
				<entry key-ref="userServiceByComplexBeanOutside" value-ref="userDaoByComplexBeanOutside"></entry>  <!-- 键值均是引用数据类型 -->
			</map>
		</property>
		<property name="props">
			<props>     <!-- properties类型需要用props标签嵌套prop标签,并在prop标签中写值,在prop的参数key中写键 -->
				<prop key="username">root</prop>
				<prop key="password">admin</prop>
				<prop key="usergroup">rootgroup</prop>
			</props>
		</property>
		
	</bean>
</beans>
// 测试类代码
package com.tech.junit;

import java.util.Map;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.tech.complexbean.ComplexBean;
import com.tech.dao.UserDao;
import com.tech.service.UserService;

public class SpringTest {
	
	@Test
	public void test07(){
		
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		ComplexBean complexBean = (ComplexBean)context.getBean("complexBean");
		
		System.out.println("-------objArray--------");
		for (Object obj : complexBean.getObjArray()) {  // 遍历objArray数组
			System.out.println(obj);
		}
		
		System.out.println("---------list---------");	
		//System.out.println(complexBean.getList());	          // 这里可以直接打印
		for (int i = 0; i < complexBean.getList().size(); i++) {  // 也可以用for遍历list
			System.out.println(complexBean.getList().get(i));
		}
		
		System.out.println("---------set---------");
		for (Object obj : complexBean.getSet()) {  // 这里使用for遍历set
			System.out.println(obj);
		}
		
		System.out.println("---------map---------");	
		for (Object obj : complexBean.getMap().keySet()) {  // 使用for遍历keySet,然后在输出对应value
			System.out.println(obj + " : " + complexBean.getMap().get(obj));
		}
		
		System.out.println("-------properties-------");
		for(Object obj : complexBean.getProps().keySet()){  // Properties类型也是Map的一种,可以以相同遍历方式遍历properties
			System.out.println(obj + " : " + complexBean.getProps().get(obj));
		}		
	}
}

控制台打印结果
Assignment and printing of complex data types

3 基于注解的bean对象创建

3.1 基础例子

  1. 第一步

    导jar包spring-aop-4.0.0.RELEASE.jar,另外必导的5个jar包前篇已经说过。

  2. 第二步

    在Spring的配置文件中配置扫描包的标签context:component-scan

    注意,需要在beans标签中添加一个参数xmlns:context值为http://www.springframework.org/schema/context

<!-- applicationContext.xml部分代码 -->

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">

	<context:component-scan base-package="com.tech"></context:component-scan>

</beans>

context:component-scan标签有一个参数为base-package,它指的是要扫描的包,填写包名,程序会扫描该包及其子包下的所有加了@Component注解的类

  1. 第三步

    在类上加@Component注解

    这里仅提供演示,在实际开发中并非这样写。

@Test
public void test08(){
		
	ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
	UserService userService = context.getBean(UserService.class);
		
	System.out.println(userService);		
}

Component annotation demonstration printing

3.2 常见的Bean注解

@Controller  // 表示会在容器中生成web层(控制层或者表示层)组件
@Service     // 表示会在容器中生成service层(业务逻辑层)组件
@Repository  // 表示会在容器中生成dao层(持久化层)组件
@Component   // 表示会在容器中生成普通组件
  • 以上四个注解注释的类均会在容器中生成bean对象,且默认bean对象的id参数的值为首字母小写的简类名。

  • 但是,也可以通过添加注解的value属性值的方式来更改bean对象的参数id的值。例如:

@Controller(value="abc")
@Service(value="def")
@Repository(value="ghi")
@Component(value="jkl")
  • 需要了解的是,通过注解创建的bean对象也是在容器加载时通过无参构造器创建的单例对象。如果你想更改创建时机和创建模式可以使用@Scope注解来更改。Scope注解的value值和2.4小节的一样。
@Scope(value="request")    // 表示每一个request请求创建一个对象
@Scope(value="session")    // 表示每一个session会话创建一个对象
@Scope(value="singleton")  // scope的默认值,表示该对象在容器加载的时候创建且单例
@Scope(value="prototype")  // 表示该对象在从容器中获取bean对象的时候才创建且多例

3.3 使用注解对变量注入

@Value("")    // 给非引用类型赋值,写在定义语句上方
@Autowire     // 给引用类型赋值,写在定义语句上方,是Spring jar包中的
@Resource     // 同Autowire注解使用方法一模一样,jdk自带的

用以上两个注解可以给bean属性赋值,Value注解例子如下

// User.java 全部代码
package com.tech.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class User {

	@Value("1101")
	private String uid;
	@Value("123456")
	private String password;
	@Value("admin")
	private String uname;
		
	public String getUid() {
		return uid;
	}
	public void setUid(String uid) {
		this.uid = uid;
	}
	public String getPassword() {
		return password;
	}
	public void setPassword(String password) {
		this.password = password;
	}
	public String getUname() {
		return uname;
	}
	public void setUname(String uname) {
		this.uname = uname;
	}
	
	@Override
	public String toString() {
		return "User [uid=" + uid + ", password=" + password + ", uname="
				+ uname + "]";
	}

}

applicationContext.xml配置文件保持不变

// 测试方法照常写
package com.tech.junit;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.tech.pojo.User;

public class SpringTest {

	@Test
	public void test09(){
		
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		User user = (User)context.getBean("user");
		
		System.out.println(user);
		
	}
	
}

结果打印
Assign values to bean properties with value annotation

Autowire注解例子如下

// UserDao.java 全部代码
package com.tech.dao;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import com.tech.pojo.User;

@Repository
public class UserDao {
	
	@Autowired
	private User user;

	public User getUser() {
		return user;
	}

	public void setUser(User user) {
		this.user = user;
	}

	@Override
	public String toString() {
		return "UserDao [user=" + user + "]";
	}
	
}
// 测试方法
package com.tech.junit;

import java.util.Map;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.tech.dao.UserDao;
import com.tech.pojo.User;

public class SpringTest {

	@Test
	public void test09(){
		
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		UserDao userDao = (UserDao)context.getBean("userDao");
		
		System.out.println(userDao);
		
	}	
}

控制台打印
Assigning bean properties with autowire annotation

  • Autowire注解的实现原理

    根据属性类型去容器中找到该类型的唯一bean对象。如果找不到,直接报NoSuchBeanDefinitionException。如果找到多个bean对象,会根据属性的名字在容器中找id值和属性名一样的bean对象,如果找不到一致的名字,还会报错,如果有一致的名字,就成功将其赋值。

4 加载properties和连接数据库

  1. 在开始这一步前,请确认导入以下两个jar包
    c3p0-0.9.1.2.jar
    mysql-connector-java-5.1.42.jar
    请确认自己jar包的版本和数据库的版本

  2. 在src目录下创建db.properties文件后在其中写入数据库信息

jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost/databasename
jdbc.username = root
jdbc.password = 123456
  1. 在配置文件中添加context:property-placeholder标签
<context:property-placeholder location="classpath:db.properties" />
  1. 在配置文件中创建ComboPooledDataSource的bean对象,并为其属性赋值,可以用EL表达式赋值
<bean class="com.mchange.v2.c3p0.ComboPooledDataSource">
	<property name="user" value="${jdbc.username}"></property>
	<property name="password" value="${jdbc.password}"></property>
	<property name="jdbcUrl" value="${jdbc.url}"></property>
	<property name="driverClass" value="${jdbc.driver}"></property>
</bean>

<!-- 注意property的value参数是EL表达式,其中的键要和db.properties中的键对应 -->
  1. 编写测试类检查连接情况
package com.tech.junit;

import java.sql.Connection;
import java.sql.SQLException;
import java.util.Map;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.mchange.v2.c3p0.ComboPooledDataSource;

public class SpringTest {
	
	@Test
	public void dbTest01() throws SQLException{
		
		ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		// 通过容器获取bean对象
		ComboPooledDataSource cpds = (ComboPooledDataSource)context.getBean("comboPooledDataSource");
		
		// bean对象调用getConnection方法过去连接的包装类
		Connection conn = cpds.getConnection();
		
		// 打印Connection对象,如果可以打印出来类地址,说明连接成功
		System.out.println(conn);
		
	}
	
}
  1. 运行测试方法打印结果

Loading properties and connecting database console to print

下一篇《Spring之面向切面编程》

# Java # Spring # Spring Framework
Eclipse右键新建文件备选项编辑
Spring学习笔记-AOP
  • 文章目录
  • 站点概览
优律

优律

优律的知识库

77 日志
20 分类
44 标签
E-mail Twitter Instagram
Links
  • CZLisyx - 浮生志
  • Vedfolnir
0%
© 2019 — 2023 萤火小屋——优律的博客网站
网站已勉强运行 
Halo博客系统技术支持