Spring 是一个框架(Framwork),主要是要从三个维度(面向对象,
面向切面,面向服务)通过整合一定的资源解决软件中的一些
相关问题.
从细节上spring核心主要解决如下几个问题:
1) 对象的创建(通过工厂创建)
2) 对象的管理(重点管理对象依赖关系)
3) …
回顾我们需要一个对象时,是如何创建对象的?
1) 直接创建(例如 new Point())
2) 通过静态工厂(例如 Calendar.getInstance(),JdbcUtil.getConnection())
3) 通过动态工厂(基于配置与反射实现对象的创建,
例如ApplicationContext 本质上就是一个动态工厂,具体可参考课堂
项目案例)
动态工厂涉及到的知识点:
1) 配置文件(xml)
2) 流对象应用(IO)
3) xml文件的解析(dom4j,扩展了解sax,pull)
4) 反射技术(Class)
1.1.1. Spring 应用动机?
Spring 在JavaEE体系中最主要的动机是整体企业可整合资源然后提供
一套完整的解决方案,例如.
1) 整合web技术,提供一套MVC架构应用
2) 整合JDBC功能,提供一套数据持久化方案
3) 整合安全框架(例如shiro),提供一套权限控制方案
4) 整合定时任务调度框架,提供一套任务调度方案
5) 整合消息中间件JMS,提供一些高并发处理方案
6) ……………………..
回顾:Java中的定时任务如何实现?(Timer, ScheduledExecutorService)
1.1.2. Spring 基本架构?
架构图中先了解如下几个部分
1) IOC (控制反转)
2) AOP (面向切面)
3) WEB (WEB-MVC)
4) ORM (对象关系映射)
5) …….
2. Spring IOC 基础应用
2.1. Spring IOC 概述
Spring IOC 是实现了控制反转功能的一个容器对象,它要通过这个对象
实现对象之间依赖关系的管理.目的主要是实现对象之间解耦合.以提高程序
的可维护及可扩展性.
Spring中的IOC功能如何实现?(借助DI:依赖注入)
2.2. Spring Bean 容器
Spring Bean容器负责创建(底层根据元数据的描述与反射技术进行对象的创建)Bean对象,并管理bean对象.
Spring 中容器对象的父类类型为ApplicationContext类型,基于此类型Spring 容器还提供了很多具体类型,例如 ClassPathXmlApplicationContext类型.
说明:
1)何为元数据?(描述数据的数据)
2)Java中常用的元数据表示形式?(xml,注解)
2.2.1. Spring Bean 容器元数据配置
本小节基于xml方式,配置spring相关信息
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<bean id="date1"
class="java.util.Date"/>
</beans>
2.2.2. Spring Bean 容器对象的初始化
Spring 中ApplicationContext为容器类型的父类类型,在初始化时可以初始化具体的子类类型.
ClassPathXmlApplicationContext ctx=
new ClassPathXmlApplicationContext(
"beans.xml");
2.2.3. Spring Bean 容器对象的使用
Date date1=(Date)ctx.getBean("date1");
Date date2=(Date)ctx.getBean("date1",Date.class);
2.3. Spring Bean 对象
2.3.1. Spring Bean 对象命名及初始化
对象命名一般是在配置文件中通过id或name属性指定其名称.
对象的初始化一般指的是对象的构建,一般有三种方式
1) 直接通过类的构造方法
2) 直接通过类的静态方法
3) 直接通过类的实例方法
2.3.2. Spring Bean 对象的作用域
Spring中Bean对象的作用域一般是通过Bean元素的score属性进行配置,
它的值最重要的有两个:
1) singleton (单例):每次从容器获取返回的都是一个对象(
内存中此类的实例只有一份),Spring中bean的默认作用域
2) prototype (多例):每次从容器获取都会创建一个新的类的实例
说明:当spring中的对象是单例设计时,这个对象的内部实例变量操作
必须是一个原子操作,否则可能会出现线程不安全的问题.
FAQ?
何为单例,单例对象一般如何设计?
2.3.3. Spring Bean 对象的生命周期
当Spring中bean元素的作用域为singleton时,此对象的生命周期由spring管理,
假如作用域为prototype时,bean对象的创建可以由spring负责,但对象的管理
及销毁Spring不在参与.
假如对象在初始化,销毁时需要执行一些动作可以在bean元素中通过属性
init-method,destroy-method属性指定要调用的具体方法.
<bean id="helloService"
class="beans.HelloService"
scope="singleton"
init-method="doInit"
destroy-method="doDestroy"/>
2.3.4. Spring Bean 对象的延迟加载
对象的延迟加载一般指的是何时需要何时加载,这是提高系统运行时性能的一种手段.
<bean
id="helloService"
class="beans.HelloService"
scope="singleton"
init-method="doInit"
destroy-method="doDestroy"
lazy-init="true"/>
说明:spring在启动时默认会初始化所有的bean对象,假如有一些bean对象
可能长时间用不到却创建了此对象,那么一些系统资源就会被浪费,解决方案
就是将此对象的加载机制设置延迟加载.假如希望所有对象都采用延迟加载
策略可以在配置文件的根元素beans中添加一个属性default-lazy-init="true"
设置即可.
2.4. Spring Bean依赖
2.4.1. 依赖基础
FAQ
- 当spring在构建对象时如何为对象的属性赋值?(set,构造方法)
- 当spring初始化一个bean对时假如还需要依赖其它对象如何实现?
Spring 中对象属性及以关系的注入方式有两种:
- Set 注入 (通过对象的set方法为参数赋值)
- 构造注入 (通过对象的构造方法为参数赋值)
2.4.2. 依赖高级
2.4.3. 自动装配
Spring 会根据Bean中的相关方法对Bean中的相关元素
进行值的注入,这种方式的实现需要借助spring bean元素
中的autowire属性实现,此属性的值常用的有四个:
1)no不进行自动装配
2)byName:由spring获取bean对象中的set方法,
取方法名set单词后面的内容,第一字母小写 ,
然后根据这个名字在容器中进行查找(比对bean元素
的id),假如找到对应名字,则将这个名字对应的
对象注入给对应set方法的参数. 也有可能找到了
名字相同但类型不同的对象,此时就会抛出异常.
3)byType:由spring获取bean对象中的set方法,
取方法中参数的类型, 然后根据这个类型在容器中
进行查找(比对bean元素的类型),假如找到对应类型,
则将这个类型对应的 对象注入给对应set方法的参数.
也有可能找到了类型相同的多个对象,此时就会抛出异常.
4)constructor:由spring获取bean对象中所有的构造
函数,依据构造函数中参数的类型在spring容器查找
相匹配的对象,找到则注入,没找到则不执行.假如找到
多个则先进行参数名匹配,名字也不匹配则不进行注入
3. Spring IOC注解应用
3.1. Spring 配置组件扫描
Spring中对Bean元素的配置提供了两种方式,一种是
基于xml方式,一种是基于注解方式.基于注解方式取
实现Bean对象的管理时,首先需要配置对bean的扫描
,就是告诉spring哪些对象需要交给spring管理.告诉
的方式也有两种,第一种方式是直接在spring的配置文件
中借助如下标签进行配置:
<context:component-scan
base-package="cn.tedu.project"/>
spring容器在初始化,会解析此xml文件,然后获取包信息
然后基于包信息从对应目录查找对应class文件.这些class
文件并不一定都是由spring管理,spring只负责管理有特定
3.2. Spring 系统组件应用
3.2.1. Spring 常用注解标记
Spring 中为了基于注解式配置和管理bean组件,推出了几个
用于描述bean组件的特定注解.常用的有:
|
注解名 |
说明 |
@Component |
通用注解 |
|
@Repository |
持久层组件应用注解 |
|
@Service |
业务层组件应用注解 |
|
@Controller |
控制层组件应用注解 |
以上注解的功能是一样的,只是描述的对象不同而已.在实际项目中通常会采用
分层架构的设计思想,最常用的分层架构就是MVC架构.而用于描述我们的bean组件的这些注解,通常会应用在MVC个组件对象中.例如web阶段最简单MVC架构图下:
此图中的Servlet一般充当MVC中的控制层对象,图中的Model可以
包含业务层对象,数据层对象.图中的JSP封装的视图逻辑.
例如:
数据层对象(封装数据逻辑,例如JDBC操作)
@Repository
public class SysUserDaoImpl implements SysUserDao{
public void saveUser(Object obj) {
System.out.println("dao.save.user");
}
}
业务层对象(封装业务逻辑,例如对用户权限进行检测,对操作进行日志记录)
@Service
public class SysUserServiceImpl implements SysUserService{
…
}
控制层对象(封装控制逻辑,例如请求处理,请求的响应)
@Controller
public class UserController {
}
视图层对象(一般封装视图逻辑,例如数据的呈现)
3.2.2. Spring 注解标记命名
在spring应用中,使用Spring注解描述的类,在构建对象进行存储时,都会默认给定
一个名字,这个名字就是所描述类的类名,并且类名的第一个单词的首字母小写.
例如:现有一个controller对象
@Controller
public class UserController {
}
使用@Controller注解修饰的UserController类,底层创建对象时,给对象起的名字为userController.假如不想使用这个名字,可以在使用注解描述类时,指定其名称.
例如:
@Controller(“userc”)
public class UserController {
}
此时这个controller对象在存储时,它的名字为userc,但实际应用中我并建议这么做,建议按默认名字.
3.2.3. Spring 注解标记作用域
使用Spring 注解标记描述的类,通常是要交给spring管理的,spring管理这些bean组件时,会按指定作用域进行管理.假如基于注解方式定义bean组件的作用域
需要使用@Scope注解,例如
@Scope(“singleton”)
@Controller
public class UserController {
}
对于这个UserController对象现在默认的作用域时单例,且生命周期由Spring管理.假如没有指定作用域默认就是singleton.
对一个Bean对象,假如希望这个对象是多例的我们可以使用@Scope(“prototype”)进行修饰.
3.2.4. Spring 注解标记延迟加载
延迟加载是很多框架中都会采用的一种技术,是从资源使用角度延迟对对象的创建.对象假如很长时间不使用,而且创建出来了,可能会占用系统中的很多资源.尤其是一些大对象(占用资源比较多的对象),一般都会采用延迟记载.具体基于注解
如何定义这个组件要采用延迟加载策略,可采用@Lazy(value=true)这种方案,当然
我们可以定义全局的延迟加载策略(在xml的beans元素内部进行定义).
@Lazy(value=true)
@Scope(“singleton”)
@Controller
public class UserController {
}
回顾:xml中全局延迟加载策略的定义
3.2.5. Spring 注解实现依赖注入
实际项目中我们通常会采用分层的设计思想,每一层对象都有它自己的一个
职责,然后这些对象相互关联,共同完成一个具体的业务,例如购物车业务,订单
业务.我们在基于注解方式配置对象依赖时,spring中可使用
@Autowired/@Qualifier,@Resource注解在对象的属性,构造方法
或set方法上进行声明。
位置使用说明
1)@Autowired/@Qualifier 应用在属性或构造方法上
2)@Resource一般应用在属性火set方法上.
应用规则说明:
通过@Autowired实现对象属性值的注入默认是按属性类型进行值的注入,假如
类中提供了与此属性有对应关的系构造函数则执行这个构造函数直接对属性
初始化,如果没有,底层通过反射获得属性类型以后,然后从容器中查找与此类型匹配的对象为其注入值.当按类型进行注入时,假如容器中存在多
个类型相同的对象时可能会注入失败,此时还可以借助@Qualifier这个注解指定
按名字进行注入(提示:在使用@Qualifier注解时前提必须已经使用了@Autowired注解),假如没有使用@Qualifier注解,此按默认属性名进行查找.
@Resource 註解一般用在屬性或set方法上用于为对象参数赋值,规则是假如这个注解中指定了名称,则只按注解中的name属性对应值
查找对象,然后进行值得注入.假如注解中没有指定名称,先按变量名进行查找,假如没找到,则按类型查找.假如Spring发现某个set方法上有此注解,则会
直接调用set方法为属性赋值.
Ÿ @Autowired注解应用
@Service
public class SysUserServiceImpl implements SysUserService{
@Autowired
private SysUserDao userDao;
public void saveUser(Object obj) {
userDao.saveUser(obj);
}
}
其中@Autowire注解默认按类型进行注入,假如希望按名字进行注入,可以再结合@Qualifier一起使用,例如
@Service
public class SysUserServiceImpl implements SysUserService{
@Autowired
@Qualifier("userDaoImpl")
private SysUserDao userDao;
public void saveUser(Object obj) {
userDao.saveUser(obj);
}
}
Ÿ @Resource注解应用
@Controller
public class SysUserController {
@Resource
private SysUserService userService;
public void doSaveUser(Object obj) {
userService.saveUser(obj);
}
}
其中@Resource属于JavaEE中的一个注解,默认按对应的属性名进行装配注入,假如希望指定的名称进行注入,可通过注解中的name属性进行配置,例如
@Controller
public class SysUserController {
@Resource(name="userServiceImpl")
private SysUserService userService;
public void doSaveUser(Object obj) {
userService.saveUser(obj);
}
}
3.2.6. Spring 注解中表达式应用
4. 总结
4.1. 课后作业
4.1.1. Day01 作业
- 自己完成写一个Spring工厂(基于xml方式)
- 掌握课堂编写的Spring基本案例
- 尝试基于注解的形式写一个Spring工厂
1) 给定一个包,包中几个类
2) 定义一个工厂,扫描指定包中的类
3) 基于反射构建所有类的对象
4) 将对象存储于工厂对应的容器中(Map类型)
4.1.2. Day02作业
- 总结课堂知识点
- 完成课堂案例
- 尝试实现依赖高级部分的依赖注入
4.1.3. Day03作业
- 掌握基于xml自动装配机制
- 总结集合注入的几种方式
- 理解基于包的扫描机制构建类的对象
- 完成课堂基于注解的对象构建
- 预习基于注解的对象依赖关系设置
4.1.4. Day04 作业
- 总结整理课堂内容到文档中
- 完成课堂案例
- 尝试基于反射给对象中的一个私有属性赋值
- 课后了解代理模式
4.1.5. Day05 作业
1.总结课堂spring注解应用
2.完成课堂mvc案例
3.理解单例的设计思路
4.课后了解代理模式.
4.2. 重点和难点分析
4.2.1. Day01 重点难点
4.2.2. 1.1.2 Spring 应用动机 1) 优化对象创建、管理,降低侵入性。 2) 简化应用开发,降低耦合。 3) 解耦并提供整体解决方案
实际企业项目开发中我们通常会借助Spring整合hibernate,mybatis等技术框架实现快速高效开发。
|
4.2.3. Day02 重点难点
- Spring Bean对象的命名及初始化
- Spring Bean对象的作用域及生命周期
- Spring Bean对象的延迟加载
- Spring Bean对象的依赖注入(set注入,构造注入)
- Spring Bean 对象的自动装配
- Spring Bean中集合注入如何实现
- Spring Bean 中表达式的基本应用
- Spring Bean 中修饰bean注解标记常用的有哪些?
- Spring Bean 中注解修饰的Bean是如何命名的?
4.2.4. Day03 重点难点
4.2.5. Day04 重点难点
- Spring Bean 中基于注解方式如何定义bean的作用域
- Spring Bean 中基于注解方式如何实现延迟加载
- Spring Bean 中基于注解方式如何实现依赖注入
- Spring Bean 中@Value注解如何应用(了解)
4.3. 常见FAQ
4.3.1. Day01 FAQ
|
4.3.2. Day02 FAQ
- Spring Bean对象默认的作用域是什么?
- Spring Bean 的作用域为singleton时,Bean对象有什么特点?
- Spring Bean 元素配置的作用域为prototype时,
Bean对象有什么特点?
- Spring Bean 元素中如何配置bean的生命周期方法?
- Spring Bean 为单例时,是否可能会存在线程安全问题?
- Spring Bean 中延迟加载机制有什么好处,如何配置?
- Spring 中依赖注入的方式有哪些?
- Spring 中的Set注入有什么特点?
- Spring 中的构造注入有什么特点?
- Spring 中的自动装配如何理解?
4.3.3. Day03 FAQ
- 何为Spring Bean容器?
用于创建bean对象,管理bean对象的那个容器
- Spring Bean容器与Spring IOC 容器有什么不同吗?
Spring IOC 容器本质上指的的就是Spring Bean容器,
Spring Bean容器中最核心一个机制是IOC机制(
控制反转),所以有时候又将springbean容器称之为
Spring IOC 容器.
- Spring IOC 如何理解?
IOC 是Spring中提供一种控制反转机制,目的是将我们
项目中对象的依赖管理交给Spring实现,这样可以更好
实现对象关系的解耦,提高程序的可扩展性.
- Spring DI 如何理解?
DI 是Spring中的依赖注入机制,IOC的实现需要借助
这种机制.我们通常会这样理解,Spring Bean容器中的
IOC思想一种目标,DI是实现这种思想的目标的手段.
- Spring 中配置bean的方式有几种?
两种,基于xml和基于注解方式
- Spring基于xml方式和基于注解方式配置bean对象时
有什么优缺点吗?
Xml:优点代码侵入性小,缺点是灵活不太好.
注解:优点灵活性比较好,缺点是存在一定的代码侵入性.
提示:基于注解方式虽然具备一定的代码侵入性,但是这种
侵入性输入声明式侵入性,这种侵入性在程序中是允许的.
它属于弱侵入性.
- 尝试自己写过SpringBean容器吗?写过
基于xml方式(xml解析+反射)
基于注解方式(反射)
- Spring中集合的注入的方式?(map,list,set,数组)
- Spring 中依赖注入表达式的应用? #{key.fileKey}
- Spring 中修饰类的注解常用的有哪些?
- Spring 中基于注解如何配置对象作用域?
4.3.4. Day04 FAQ
@Scope(“singleton”)
@Scope(“prototype”)
- Spring 中基于注解如何配置延迟加载机制?
@Lazy(value=true)
- Spring 中对象依赖关系的注入有哪些方式?
Set注入
构造注入
- Spring 中基于注解方式实现依赖关系注入时,有哪些常用注解?
- Spring 中@Resource与@Autowire注解应用时有什么异同点
- Spring 中@Value注解有什么作用.
-
使用spring 的注解 @value使用方法
有三种,都没测试
1 中#################
在spring 3.0中,可以通过使用@value,对一些如xxx.properties文件
中的文件,进行键值对的注入,例子如下:
1 首先在applicationContext.xml中加入:
<beans xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.1.xsd">
</beans>
的命名空间,然后
2
<util:properties id="settings" location="WEB-INF/classes/META-INF/spring/test.properties" />
3 创建test.properties
abc=123
4
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@RequestMapping("/admin/images")
@Controller
public class ImageAdminController {
private String imageDir;
@Value("#{settings['test.abc']}")
public void setImageDir(String val) {
this.imageDir = val;
}
}
这样就将test.abc的值注入了imageDir中了2 中##########################
<context:property-placeholder location="classpath*:sysconfig.properties"/>;
3 中 ###############直接用类
- public class abcextends PropertyPlaceholderConfigurer {
- private static HashMap<String, String> ctxPropertiesMap;
- @Override
- protected void processProperties(
- ConfigurableListableBeanFactory beanFactory, Properties props)
- throws BeansException {
- super.processProperties(beanFactory, props);
- ctxPropertiesMap = new HashMap<String, String>();
- for (Object key : props.keySet()) {
- String keyStr = key.toString();
- String value = props.getProperty(keyStr);
- ctxPropertiesMap.put(keyStr, value);
- }
- }
- public static String getProperty(String name) {
- return ctxPropertiesMap.get(name);
- }
- public static boolean getPropertyMapKey(String key) {
- if (ctxPropertiesMap.containsKey(key)) {
- return true;
- }
- return false;
- }
- public static void writePropertyByKey(String key, String value) {
- ctxPropertiesMap.put(key, value);
- }
- }
<bean class="sdewwwww">
<property name="locations">
<list>
<value>classpath:FrontService.properties</value>
<value>classpath:ResponseCode.properties</value>
</list>
</property>
</bean>