1 Spring概述
1.1 Spring简介
Spring实际上是一个企业级开发的免费开源的Java框架,用来简化java开发的。总之:spring是一个基于IOC和Aop的容器框架。
Spring框架的官网:https://spring.io/projects/spring-framework
点击访问
1.2 Spring三层架构
层 | 表示层→ | →业务逻辑层→ | →持久化层 |
---|---|---|---|
具体名称 | web层(控制层) | service层 | dao层 |
作用 | 接收、处理并响应请求 | 处理业务逻辑 | 和数据库相连接 |
模块 | SpringMVC | 声明式事务 | JDBCTemplate |
注意:Spring Framework跨三层,不属于任意一层。SpringMVC其实是Spring Framework中的一个模块,但在开发中会被当做一个单独的框架。
分层的目的:解耦合
1.3 Spring两大部分
- IOC(控制反转)
- 具体实现:DI
- XML
- 注解
- 具体实现:DI
- AOP(面向切面编程)
- 具体实现:
- XML
- 注解
- 具体实现:
1.4 Spring Framework的模块划分
模块说明
1.5 Spring Framework的jar包
-
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 是上边四个的依赖
-
每个jar包不同的版本
用core核心包来举例
spring-core-4.0.0.RELEASE.jar | spring-core-4.0.0.RELEASE-javadoc.jar | spring-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 获取容器对象的三种方式
- 在类路径下寻找配置文件来实例化容器
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); //使用applicationContext加载spring容器
ApplicationContext context = new ClassPathXmlApplicationContext(new String[]{"com/test/ac/beans.xml"}); //如果定义成数组一次可以加载多个spring容器
// 使用context.getBean(Object.class);可以获取容器中的类对象
- 在文件系统路径下寻找配置文件来实例化容器
ApplicationContext context = new FileSystemXmlApplicationContext("D:\\TestSpring\\SpringBean\\src\\com\\test\\ac\\beans.xml");
- 使用BeanFactory(已过时,不推荐使用)
BeanFactory factory = new XmlBeanFactory(new FileSystemResource("D:\\TestSpring\\SpringBean\\src\\com\\test\\ac\\beans.xml"));
- 方法总结
2.3 从容器中获取bean对象的两种方式
- 通过字节码方式
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
Test01 t1 = context.getBean(Test01.class);
- 通过容器中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对象创建原理
- 创建时机:默认为加载容器的时候
- 底层原理:反射
- 是否单例:默认为单例
- 修改其创建时机和是否单例
需要在bean标签中设置scope属性
<bean id="test1" class="com.test1.Test01" scope="singleton"></bean>
scope有四个值
request | session | singleton | prototype |
---|---|---|---|
表示每一个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
- 外部bean:在
<beans>
标签内部直接定义的bean对象叫外部bean,外部bean可以被多次引用。 - 内部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 容器创建对象的三种方式
- 构造器
一般情况下使用的方法,例子如下
// 测试类中的测试方法(部分)
@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>
- 静态工厂
通过类得静态方法得到的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");
}
控制台打印
- 实例工厂
调用一个对象的普通方法返回的一个对象,这里用的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");
}
结果打印
2.9 属性赋值
2.9.1 按属性类型划分
-
值注入
基本数据类型及其对应的包装类,例如:Integer。String类型也在其中。 -
引用注入
数据是引用类型
举例:
<!-- 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);
}
控制台打印
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);
}
控制台打印结果
注意:当类有两个或多个仅仅是参数顺序不一致的构造器的时候,程序默认总是选择最后一个。例子如下。
// 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);
}
控制台打印信息
那么该如何手动选择使用的构造器呢?答案是,在<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>
再次打印看看
如我们所愿,这次选择了第一个构造器来赋值。
另外,在<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>
打印结果
综上<constructor-arg>
参数汇总
参数 | name | value | ref | index | type |
---|---|---|---|---|---|
解释 | 参数的名字 | 参数的值,仅在参数为非引用类型时使用 | 引用值,仅在参数为引用类型时使用,即该参数是个bean | 指定使用构造器的索引,从0开始 | 指定参数的类型 |
2.9.2.2 set方法注入
- property标签
在DI简介中曾有过例子,该方法会调用类中的set方法为属性赋值。 - 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 + "]";
}
}
控制台打印
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));
}
}
}
控制台打印结果
3 基于注解的bean对象创建
3.1 基础例子
-
第一步
导jar包spring-aop-4.0.0.RELEASE.jar,另外必导的5个jar包前篇已经说过。
-
第二步
在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
注解的类
-
第三步
在类上加
@Component
注解这里仅提供演示,在实际开发中并非这样写。
@Test
public void test08(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = context.getBean(UserService.class);
System.out.println(userService);
}
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);
}
}
结果打印
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);
}
}
控制台打印
-
Autowire注解的实现原理
根据属性类型去容器中找到该类型的唯一bean对象。如果找不到,直接报NoSuchBeanDefinitionException。如果找到多个bean对象,会根据属性的名字在容器中找id值和属性名一样的bean对象,如果找不到一致的名字,还会报错,如果有一致的名字,就成功将其赋值。
4 加载properties和连接数据库
-
在开始这一步前,请确认导入以下两个jar包
c3p0-0.9.1.2.jar
mysql-connector-java-5.1.42.jar
请确认自己jar包的版本和数据库的版本 -
在src目录下创建db.properties文件后在其中写入数据库信息
jdbc.driver = com.mysql.jdbc.Driver
jdbc.url = jdbc:mysql://localhost/databasename
jdbc.username = root
jdbc.password = 123456
- 在配置文件中添加context:property-placeholder标签
<context:property-placeholder location="classpath:db.properties" />
- 在配置文件中创建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中的键对应 -->
- 编写测试类检查连接情况
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);
}
}
- 运行测试方法打印结果