Spring框架详解(一)

一、 概述

1.1 Spring介绍

Spring框架是目前最流行的JavaEE开源框架之一。它的核心功能是IoC(Inverse Of Control:控制反转)和AOP(Aspect Oriented Programming:面向切面编程)。除此以外,Spring还提供了Spring MVC、Spring JDBC,以及业务层事务管理等众多出色的企业级应用技术,它还能整合开源世界众多著名的第三方框架和类库。

1.2 Spring的下载和安装

下载地址:
http://repo.springsource.org/libs-release-local/org/springframework/spring/

下载完成后,直接解压缩即可,无需安装。
在这里插入图片描述
docs:api和开发规范;
libs:jar包和源码包;
schema:约束文件;

1.3 入门示例

1.3.1 环境准备

第一步:把Spring的核心jar包导入到工程中;
在这里插入图片描述
除此以外,我们还需要导入commons-logging的jar包。由于Spring本身并没有提供该jar包,需要用户自行在网上下载。

第二步:定义一个Bean类。

class UserBean {
	
	public void sayHi() {
		System.out.println("hello boys");
	}

}

第三步:配置上面定义的Bean。

在src目录下新建一个xml文件,并命名为“beans.xml”。然后,在该文件中配置上面定义的bean。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
      					 http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="userBean" class="com.xjy.demo01hellospring.UserBean"/>
</beans>

1.3.2 编写测试代码

第一步:创建ApplicationContext对象。这里我们使用它的实现类classPathXmlApplicationContext,该类可以从类加载路径下加载xml格式的配置文件。
第二步:调用ApplicationContext对象的getBean方法,该方法用于获取指定id的bean对象;
第三步:调用bean对象方法;

public class Demo01 {

	public static void main(String[] args) {
		//1.加载Spring配置文件
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
		//2.根据bean的id获取对象
		UserBean userBean = (IUserDao) ac.getBean("userBean");
		userBean.sayHi();
	}

}

第四步:测试。

1.4 Bean的配置

如果需要把一个对象交给Spring容器来管理,那么就需要在Spring配置文件的Bean节点对该对象进行配置。

  • 配置Bean的语法格式:
<bean id=”” class=”” scope=””/>

参数说明:

  • id:对象的唯一标识。Spring用户会根据ID的值创建对象。

  • class:对象所在类的完整类名。

  • scope:对象的作用范围。该属性的取值为:
    1)singleton:默认值,服务器启动时候,Spring容器中就会创建一个对象。如果指定了singleton,那么在Spring容器中只有一个Bean对象。
    2)prototype:每次调用获取Bean对象的时候,Spring容器都会创建一个Bean对象。
    3)request:在web项目中,该对象只在Request中有效。
    4)session:在web项目中,该对象只在Session中有效。
    5)globalSession:在web项目中,该对象只在Portlet环境中有效。如果没有Portlet环境,那么该作用域就相当于session。

  • init-method:指定类中初始化方法的名称;

  • destory-method:指定类中销毁方法的名称;

二、 IOC

IOC(Inversion of Control,控制反转或依赖注入)是Spring框架的核心功能之一。所谓控制反转,就是Spring容器负责创建Bean对象,并把对象传入到一个类里面,而不需要我们手动创建对象和手动把对象传入到其他类中。

依赖注入主要分为两种:构造注入和属性注入。

2.1 构造注入

顾名思义,就是使用类中的构造函数,给成员变量赋值。

例如:

public class UserBean {
	private String name;
	private int age;
	
	public UserBean(String name, int age) {
		this.name = name;
		this.age = age;
	}
	// 省略了setters和getters方法...
}

然后在Spring配置文件中配置该Bean。
```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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
      					 http://www.springframework.org/schema/beans/spring-beans.xsd">
	<bean id="userBean" class="com.xjy.beans.UserBean"/>
</beans>

运行程序发现出现了异常。

因为默认情况下,Spring容器是调用无参构造函数来创建Bean对象。上面的UserBean提供了有参构造函数,因此JVM就不会再提供无参构造函数了。

【解决办法】
办法一:提供无参构造函数;
办法二:使用构造注入;

构造注入需要在bean标签中使用constructor-arg标签来配置构造函数中的每一个参数。例如:

<bean ...>
	<constructor-arg name=”” value=”” index=”” type=”” ref=””></bean>

参数说明:
name:参数名;
value:参数值;
index:参数的下标;
type:参数类型;
ref:引用其他bean对象;

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
      					 http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="userBean" class="com.xjy.beans.UserBean">
		<!-- 根据下标设置参数
		<constructor-arg index="0" value="小宝"/>
		<constructor-arg index="1" value="18"/> -->
		
		<!-- 根据名字设置参数
		<constructor-arg name="name" value="小宝"/>
		<constructor-arg name="age" value="18"/> -->
		
		<!-- 指定参数类型 -->
		<constructor-arg name="name" value="小宝" type="java.lang.String"/>
		<constructor-arg name="age" value="18" type="int"/>
		<constructor-arg name="birthDate" ref="now"/>
	</bean>
	
	<bean id="now" class="java.util.Date"/>
</beans>

2.2 属性注入

  • 语法格式:
<bean >
	<property name=”” value=”” ref=””/>
</bean>

参数说明:
name:属性名。注意:Spring是根据setter方法来判断属性的。
value:属性值。
ref:引用其他bean对象。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
      					 http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="userBean" class="com.xjy.beans.UserBean">
		<property name="name" value="大宝"/>
		<property name="age" value="18"/>
		<property name="birthDate" ref="now"/>
	</bean>
	
	<bean id="now" class="java.util.Date"/>
</beans>

注意:因为执行属性注入前,Spring容器会调用Bean类的无参构造函数创建对象,然后再把属性注入到该对象中。所以Bean类必须要提供一个无参构造函数。

2.3 注入集合

第一步:修改实体类。

public class UserBean {
	private String name;
	private int age;
	private Date birthDate;
	private String[] myStrs;
	private List myList;
	private Set mySet;
	private Map myMap;
	private Properties myProps;
	
	// 省略了setters和getters方法。。。
}

第二步:在beans.xml文件中配置该Bean。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
      					 http://www.springframework.org/schema/beans/spring-beans.xsd">
	
	<bean id="userBean" class="com.xjy.beans.UserBean">
		<property name="name" value="大宝"/>
		<property name="age" value="18"/>
		<property name="birthDate" ref="now"/>
		<!-- 注入数组 -->
		<property name="myStrs">
			<array>
				<value>AAA</value>
				<value>BBB</value>
				<value>CCC</value>
			</array>
		</property>
		<!-- 注入set集合 -->
		<property name="mySet">
			<list>
				<value>AAA</value>
				<value>BBB</value>
				<value>CCC</value>
			</list>
		</property>
		<!-- 注入Map集合 -->
		<property name="myMap">
			<props>
				<prop key="keyA">aaa</prop>
				<prop key="keyB">bbb</prop>
			</props>
		</property>
		<!-- 注入properties数据 -->
		<property name="myProps">
			<map>
				<entry key="keyA" value="aaa"/>
				<entry key="keyB" value="bbb"/>
			</map>
		</property>
	</bean>
	
	<bean id="now" class="java.util.Date"/>
</beans>

第三步:测试。

public class Demo02 {

	public static void main(String[] args) throws Exception {
		ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
		UserBean userBean = (UserBean) ac.getBean("userBean");
		System.out.println(Arrays.toString(userBean.getMyStrs()));
		System.out.println(userBean.getMySet());
		System.out.println(userBean.getMyList());
		System.out.println(userBean.getMyMap());
		System.out.println(userBean.getMyProps());
	}
	
}

三、使用注解

Spring框架还支持通过注解方式注入Bean对象。

  • 使用注解方式的好处:

1) 简单,方便维护;
2) 方便查看。查看源码的时候就可以看到Bean的配置信息。

3.1 使用注解的步骤

第一步:把注解相关的jar包导入到工程中;
在这里插入图片描述

第二步:在spring配置文件中加入context命名空间,然后开启注解功能。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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.xsd">
	
	<context:component-scan base-package="com.xjy.beans"/>
	
</beans>

第三步:在注入资源的类上使用@Component注解;
在这里插入图片描述

第四步:测试。

public class Demo03 {

	public static void main(String[] args) {
		ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
		UserBean userBean = (UserBean) ac.getBean("userBean");
		System.out.println(userBean);
	}
	
}

3.2 常用注解

3.2.1 Bean注解

Bean注解包括:@Component、@Controller、@Service、@Repository。它们都可以定义在类上面。而且它们的作用都是一样的,都是让资源交给Spring来管理。只不过它们各自提供了更加明确的语义。

例如:@Service是一般是用来修饰业务类。
在这里插入图片描述
value属性:指定资源的名字。可以省略value不写。如果没有指定资源名字,那么默认就是类型名,然后首字母小写,例如:userService。

3.2.2 @Autowired

如果在成员属性上使用该注解,那么服务器启动的时候,Spring容器就会自动查找该类型以及它的子类型。如果找到就会创建该类对象,并且注入到该成员属性中。

@Service("userService")
public class UserService {
	//根据属性名查找Bean对象,并把该对象设置到该属性中
	@Autowired
	private IDao dao;
	
	public UserService() {
		System.out.println("创建UserService对象...");
	}
	
	public void addUser() {
		dao.add();
	}
	
}

@Repository
public class StudentDaoImpl implements IDao {
	
	public StudentDaoImpl() {
		System.out.println("创建StdentDaoImpl对象...");
	}

	public void add() {
		System.out.println("执行StdentDaoImpl对象的add方法...");
	}
	
}

当使用注解注入属性时,set方法可以省略。但是,如果存在两个或两个以上的子类型,那么就会出现NoUniqueBeanDefinitionException异常。例如:
在这里插入图片描述
出现上面问题的原因:
@autowired默认是根据类型执行注入。如果该类型是接口,而接口下有多个实现类的Bean,那么Spring容器就无法自动识别出注入哪个类型的Bean对象。

解决办法:
1)指定不同变量名;
2)使用@Qualifier指定注入Bean对象的名字;

3.2.3 @Qualifier

作用:在自动按照类型注入的基础之上,再按照Bean的名字注入。它不能独立使用,必须和@Autowire一起使用。
在这里插入图片描述

3.2.4 @Resource

通过名字注入Bean对象。该注解的功能其实就是@Autowired和@Qualifier功能的结合。
在这里插入图片描述
name属性:要注入的Bean对象的名字。

3.2.5 @Value

作用:注入基本数据类型和String类型的数据。
在这里插入图片描述

3.2.6 @Scope

作用:设置Bean的作用域。Bean的作用范围有:singleton、prototype、request、session、globalsession。
在这里插入图片描述

3.2.7 生命周期相关的注解

@PostConstruct:指定初始化方法;
@PreDestory:指定销毁方法;
在这里插入图片描述

四、Spring零配置

刚才给大家演示了如何使用注解方式注入Bean对象。当时还有一个问题,就是无法完全脱离配置文件。如果要完全脱离XML配置文件,那么还需要使用到其他一些注解。

4.1 @Configuration

作用:指定Spring容器从当前类中加载读取配置信息。

4.2 @ComponentScan

作用:指定spring容器初始化时候要扫描的包。
属性:
basePackages:指定要扫描的包。和该注解中的value属性作用一样。
在这里插入图片描述
因为没有了配置文件,所以就不能够再使用ClassPathXmlApplicationContext来创建ApplicationContext对象。而要使用AnnotationConfigApplicationContext来创建对象。
在这里插入图片描述

4.3 @PropertySource

作用:加载properties文件中的配置。
属性:
value[]:指定properties文件的位置。如果在src目录下,那么就需要加上classpath前缀。

  • 使用步骤:

首先,在src目录下创建一个info.properties配置文件。该文件保存Bean对象的属性值。
在这里插入图片描述
然后,在成员属性上使用@Value注解。
在这里插入图片描述
接着,新建一个类,该类用于定义配置信息。
在这里插入图片描述
最后,测试一下。
在这里插入图片描述

运行程序时候,控制台输出:
在这里插入图片描述
该异常是由于Spring容器并没有把${user.age}作为占位符,而是把它看成是普通字符串来解析所造成的。

解决办法:创建一个占位符的配置器,并交给Spring容器管理。

4.4 @Bean

作用:该注解只能写在方法上,表明使用此方法创建一个对象,并且交给spring管理。

该注解包含以下的属性:

  • name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)。
@Component
public class DbBean {
	
	@Bean(name="datasource")
	public DataSource createDS() throws Exception {
		ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
		comboPooledDataSource.setUser("root");
		comboPooledDataSource.setPassword("root");
		comboPooledDataSource.setDriverClass("com.mysql.jdbc.Driver");
		comboPooledDataSource.setJdbcUrl("jdbc:mysql://localhost:3306/aa");
		return comboPooledDataSource;
	}

}

public class Demo03 {

	public static void main(String[] args) throws SQLException {
		ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
		DataSource ds = (DataSource) ac.getBean("datasource");
		System.out.println(ds.getConnection());
	}
	
}

运行程序发现,Spring容器初始化的时候,就会调用DbBean中的createDs方法创建一个DataSource对象,并且把该对象交给了Spring容器管理。因此,在测试类中可以通过它的名字来访问。

我们重新再看回之前的例子。如果要创建一个占位符的配置器对象,可以在SpringConfig类中添加如下方法:
在这里插入图片描述
运行程序的时候,Spring容器就不会再把${user.age}当成普通字符串来处理,而是作为一个占位符来处理。

五、SpringTest

SpringTest是Spring框架用来做单元测试的工具。使用SpringTest需要结合Junit一起使用。

5.1 测试环境准备

5.1.1 编写实体类

public class Customer implements Serializable {
	private Long custId;
	private String custName;
	private String custSource;
	private String custIndustry;
	private String custLevel;
	private String custAddress;
	private String custPhone;

	// 省略了setters和getters方法...
}

5.1.2 编写Dao类

public interface ICustomerDao {

	/**
	 * 查询所有客户
	 * @return
	 */
	List<Customer> findAllCustomer();

	/**
	 * 保存客户
	 * @param customer
	 */
	void save(Customer customer);
	
}

public class CustomerDaoImpl implements ICustomerDao {

	@Override
	public List<Customer> findAllCustomer() {
		System.out.println("查询了所有客户");
		return null;
	}

	@Override
	public void save(Customer customer) {
		System.out.println("保存了客户");
	}

}

5.1.3 编写业务类

public interface ICustomerService {

	/**
	 * 查询所有客户
	 * @return
	 */
	List<Customer> findAllCustomer();
	
	/**
	 * 保存客户
	 * @param customer
	 */
	void saveCustomer(Customer customer);
	
}

public class CustomerServiceImpl implements ICustomerService {
	@Autowired
	private ICustomerDao customerDao;
	
	public void setCustomerDao(ICustomerDao customerDao) {
		this.customerDao = customerDao;
	}

	@Override
	public List<Customer> findAllCustomer() {
		return customerDao.findAllCustomer();
	}

	@Override
	public void saveCustomer(Customer customer) {
		customerDao.save(customer);
	}

}

5.1.4 编写测试类

在测试方法上使用@Test注解。测试方法名就是在需要测试的业务方法名前面加上test。

public class CustomerServiceTest {

	private ICustomerService customerService;
	
	@Test
	public void testFindAll() {
		List<Customer> customers = customerService.findAllCustomer();
		for (Customer customer : customers) {
			System.out.println(customer);
		}
	}
	
}

5.1.5 编写配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	   xmlns:context="http://www.springframework.org/schema/context"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       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.xsd">
	
	<bean id="customerDao" class="com.xjy.dao.impl.CustomerDaoImpl"></bean>
	
	<bean id="customerService" class="com.xjy.service.impl.CustomerServiceImpl">
		<property name="customerDao" ref="customerDao"></property>
	</bean>
	
</beans>

5.1.6 导入jar包

在这里插入图片描述

5.2 SpringTest相关注解

@RunWith:指定Junit运行器,它负责执行测试类。
@ContextConfiguration:指定Spring配置文件的位置;
在这里插入图片描述

@Autowired:指定要注入的资源;
在这里插入图片描述
在这里插入图片描述

配置完成后,打开Outline视图。然后找到要运行的方法,鼠标右键点击Run As –> Junit Test即可。
在这里插入图片描述

5.3 SpringTest零配置

如果要实现零配置,那么需要对上面程序进行简单的改造即可。实现步骤如下:

第一步:在CustomerServiceImpl上使用@Service注解。
在这里插入图片描述
这时候可以把customerDao的setter方法去掉。

第二步:在CustomerDaoImpl上使用@Repository注解。
在这里插入图片描述

第三步:修改测试类。
在这里插入图片描述

发布了111 篇原创文章 · 获赞 41 · 访问量 3万+

猜你喜欢

转载自blog.csdn.net/zhongliwen1981/article/details/99354079
今日推荐