spring 在三层架构中的位置
1.spring负责管理项目中所有的对象
2.spring看做是项目中对象的管家
侵入式设计
引入了框架,对现有的类的结构有影响,即需要实现或继承某些特定类。 例如: Struts框架
非侵入式设计
引入了框架,对现有的类结构没有影响。 例如:Hibernate框架 / Spring框架
spring是一站式框架
1.因为spring框架性质是属于容器性质的,容器中装什么对象,就有什么功能 所以可以一站式。
2.不仅不排斥其他框架 还能帮其他框架管理对象,例如: aop支持 ioc思想 spring jdbc aop事务 Junit测试支持
spring环境搭建
spring模块
在3.0以下的版本,源码有spring中相关的所有包 [spring功能 + 依赖包]
在3.0以上的版本,源码中只有spring的核心功能包 [没有依赖包]
(如果要用依赖包,需要单独下载!)
1.导jar包
bean core context spel 是我们使用spring要导入的最基本的包
还需要导入额外的 logging包 , 老版本可能还需要导入 log4j的包(一般不需要)
spring-beans-3.2.5.RELEASE.jar bean节点
spring-context-3.2.5.RELEASE.jar spring上下文节点
spring-core-3.2.5.RELEASE.jar spring核心功能
spring-expression-3.2.5.RELEASE.jar spring表达式相关表
2. 测试步骤
书写配置注册到容器 配置文件(位置任意最好是src目录下名字最好是applicationContext.xml)
最后导入bean约束 ,最后就可以测试了
public class App { public void testIOC() throws Exception { // 现在,把对象的创建交给spring的IOC容器 Resource resource = new ClassPathResource("cn/itcast/a_hello/applicationContext.xml"); // 创建容器对象(Bean的工厂), IOC容器 = 工厂类 + applicationContext.xml BeanFactory factory = new XmlBeanFactory(resource); // 通过工厂得到IOC容器 // 得到容器创建的对象 User user = (User) factory.getBean("user"); System.out.println(user.getId()); } public void testAc() throws Exception { ApplicationContext ac = new ClassPathXmlApplicationContext("cn/itcast/a_hello/applicationContext.xml"); User user = (User) ac.getBean("user"); System.out.println(user); }}
Spring提供了一站式解决方案:
1) Spring Core spring的核心功能: IOC容器, 解决对象创建及依赖关系
2) Spring Web Spring对web模块的支持。
可以与struts整合,让struts的action创建交给spring
spring mvc模式
3) Spring DAO Spring 对jdbc操作的支持 [JdbcTemplate模板工具类]
4) Spring ORM spring对orm的支持:
既可以与hibernate整合,[session]
也可以使用spring的对hibernate操作的封装
5)Spring AOP 切面编程
6)SpringEE spring 对javaEE其他模块的支持
可以解决对象创建以及对象之间依赖关系的一种框架
spring的一些概念
IOC思想 inverse of control 控制反转
将我们创建对象的方式反转,以前创建对象都是开发人员自己维护,包括依赖关系也是自己注入
使用了spring了之后 对象的创建以及依赖 都有 spring完成控制反转就是反转了对象的创建方式 返给了程序。
DI dependency injection 依赖注入
实现控制反转需要DI 做支持
实现的方式 set方法注入/构造方法注入/p名称注入/spel注入
spring对象的创建方式
1.空参数构造函数 <bean name="user" class="com.domain.User">
2.静态工厂 工厂也可以使用 初始化和销毁方法
<bean name="user" class="com.domain.UserFactory" factory-method="createUsers" init-method="init" destroy-method="destroy"> </bean>
里面 class属性指定 工厂所在的类全名 factory-method 指定 构造需要的对象的方法
ApplicationContext接口里面没有 close方法 但是他的子类里面有 测试就直接创建子类实例即可测试销毁方法
3.实例工厂
步骤:1.先创建 工厂的实例 2.然后使用factory-bean 和factory-method
<bean name="stufactory" class="com.domin.StuFactory" scope="singleton"></bean> 注意:工厂实例最好只有一个实例
<bean name="stu" class="com.domin.Student" factory-bean="stufactory" factory-method="getStu"></bean>
Applicationcontext和BeanFactory
BeanFactory接口
spring原始接口 针对原始接口的实现类功能较为单一
Beanfactory接口实现类的容器特点:每次获得对象才会创建对象(但是硬件资源稀缺)
ApplicationContext
每次容器启动时就会创建容器中配置的所有对象,并提供更多的功能
结论 : 在web开发中,使用applicationContext ,在资源匮乏的环境可以使用BeanFactory 比如:手机
实现类
从类路径下加载配置文件 ClassPathXmlApplicationContext("file")
从硬盘绝对路径下加载配置文件 FileSystemXmlApplicationContext("file")
spring 配置详解
bean元素 使用该元素描述 表示该对象是需要spring容器管理的对象
class属性:被管理对象的完成类名
name属性:给被管理的对象起个名字,根据该名称以获得对象 可以重复 可以使用特殊字符
id属性:与name属性作用一样 ,名称不能重复 不能使用特殊字符
结论:尽量使用 name属性
spring分模块配置
<import resource="/path/to/somewhere.xml"> 导入其他spring配置文件
scope 属性
singleton 默认值 单例对象 被标识为单例的对象 在spring容器中只会存在一个实例 例如:Dao
public static void testContext() { ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml"); Users u = (Users) ac.getBean("user"); Users u1 = (Users) ac.getBean("user"); System.out.println(u==u1); ->返回true} 可以使用该方式来测试
注意:整合spring和struts2的时候 ActionBean 必须配置为多例
singleton(默认值):单例.创建容器时会立即创建单例对象
prototype :多例.每次获得对象时,才会创建对象,并且每次都会创建新的对象
lazy-init="false" 默认为false, 不延迟创建,即在启动时候就创建对象
azy-init="true" 延迟初始化, 在用到对象的时候才创建对象(只对单例有效)
request:web环境下 对象与request声明周期一致(了解)
session:web环境下 对象与session声明周期一致(了解)
声明周期属性(了解)
配置一个方法作为声明周期初始化方法 spring会在对象创建之后立即调用 init-method
同理:销毁方法 spring容器在关闭并销毁容器中的对象之前调用 destory-method
<bean name="..." class="..." init-method="..." destory-method="..." ></bean>
spring属性注入
注入方式
1.set方法注入(最重要的)
也可以设置为null
property 只有三个属性 name value(基本类型注入) ref(引用类型注入)
2.构造函数注入
构造函数注入4个属性 index从0开始
1. name 属性的名字2. value/ref 基本/引用数据的值3. index 为了唯一确认 一个构造函数4. type 该字段的类型
3.p名称空间注入(优化) 实际上还是走的set方法 3.0以上版本才支持
步骤:
1.导入p名称空间 xmlns:p="http://www.springframework.org/schema/p"
2.使用 p:属性完成注入 | 值类型 p:属性名=“值” | 引用类型 p:属性名-ref="bean名称"<bean name="user" class="..." p:name="20" p:age="20" p:car-ref="car">
p名称注入 只是 set 方法注入的简便写法前提是:要有 空参数的构造函数
4.spel注入 spring expression language spring表达式语言
引用类型是不允许使用该表达式的
bean间的继承
如果多个bean存在相同的配置信息,spring允许定义一个父bean,然后为其他bean可以继承bean也可以覆盖bean中的配置信息。
就需要abstract 和 parent属性的使用
内部bean
自动装配的方式
根据名称自动装配:autowire="byName"
自动去IOC容器中找与属性名同名的引用的对象,并自动注入 属性名称和 容器中对象的名称相同 自动装配
也可以定义到全局, 这样就不用每个bean节点都去写autowire=”byName”
根据名称自动装配(全局)
根据类型自动装配:autowire="byType"
必须确保改类型在IOC容器中只有一个对象;否则报错。 类型匹配
总结:
Spring提供的自动装配主要是为了简化配置; 但是不利于后期的维护。
(一般不推荐使用)
使用注解的方式
先引入context名称空间 还需要导入 aop.jar 包
开启注解扫描
使用注解
@Component 加入ioc容器的对象的引用名称, 默认与类名一样, 且第一个字母小写
@Resource 根据类型查找 [在容器中要确保该类型只有一个变量]
@Resource(name = "userDao") 根据名称查找
复杂类型注入
数组/列表
如果数组中只准备注入一个值/对象 直接使用value| ref即可 <property name="arr" value="tom">
如果不只一个值
列表只需要将 array换成 list即可
map类型
properties类型
在WEB环境中使用Spring容器
1.导包 4+2+1(spring-web)
2.在web.xml中配置listener => ContextLoaderListener |-配置参数,指定spring配置路径 3.在Action中,使用工具类获得容器. |-WebApplicationContextUtils.getWebApplicationContext(ServletContext sc)
web.xml中配置容器随项目启动
在Action中获得容器中的Service对象
在Action中获得容器
管理容器在项目中的生命周期
这是错误的示范.导致每次请求都创建新的容器
怎么只创建一个ApplicationContext对象(使用Context监听器) spring容器已经写好了
org.springframework.web.context.ContextLoaderListener contextConfigLocation classpath:applicationContext.xml
代理模式
代理(Proxy)是一种设计模式, 提供了对目标对象另外的访问方式;即通过代理对象访问目标对象。
这样好处: 可以在目标对象实现的基础上,增强额外的功能操作。(扩展目标对象的功能)。
静态代理
可以做到在不修改目标对象的功能前提下,对目标对象功能扩展
缺点:
因为代理对象,需要与目标对象实现一样的接口。所以会有很多代理类,类太多。
一旦接口增加方法,目标对象与代理对象都要维护。
动态代理
1)代理对象,不需要实现接口
2)代理对象的生成,是利用JDKAPI,动态的在内存中构建代理对象(需要我们指定创建 代理对象/目标对象 实现的接口的类型)
3) 动态代理, JDK代理, 接口代理
JDK中生成代理对象的API
Proxy
static Object newProxyInstance
ClassLoader loader, 指定当前目标对象使用类加载器
Class<?>[] interfaces, 目标对象实现的接口的类型
InvocationHandler h 事件处理器
代理对象不需要实现接口,但是目标对象一定要实现接口;否则不能用动态代理!
Cglib代理
Cglib代理,也叫做子类代理。在内存中构建一个子类对象从而实现对目标对象功能的扩展。
CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它要求你必须对JVM内部结构包括class文件的格式和指令集都很熟悉。
Cglib子类代理
需要引入cglib – jar文件, 但是spring的核心包中已经包括了cglib功能,所以直接引入spring-core-3.2.5.jar即可。
引入功能包后,就可以在内存中动态构建子类
代理的类不能为final, 否则报错
目标对象的方法如果为final/static, 那么就不会被拦截,即不会执行目标对象额外的业务方法。
在Spring的AOP编程中 让关注点代码与业务代码分离
如果加入容器的目标对象有实现接口,用JDK代理
如果目标对象没有实现接口,用Cglib代理