本帖最后由 chenlong43210 于 2018-7-6 09:59 编辑
【石家庄校区】Spring框架知识
Spring介绍
环境搭建
jar包下载:spring.io
导入相关功能jar包和依赖jar包
创建spring配置文件,src/applicationContext.xml
dtd约束:spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html
spring在web开发中应用(整合web)
导入jar包 spring-web...
web.xml中配置
配置<listener>:org.springframework.web.context.ContextLoaderListener
ContextLoaderListener实现了ServletContextListener
服务器启动时,将ApplicationContext(实现类WebApplicationContext)存入ServletContext中
配置applicationContext.xml文件位置(默认在WEB-INFO下查找applicationContext.xmls)
<context-param>... contextConfigLocation //是在listener中声明的常量,描述spring配置文件位置
=classpath:applicationContext.xml //代表在当前工程的类路径下(可以理解成在src)下查找
Spring是一个一站式的分层轻量级框架
组成模块
Core Container(核心容器)
Beans和Core:Spring框架基本功能,提供IOC与DI
Context:上下文对象,基于beans与core
SpEL:Spring提供的一个表达式语言
Data Access/Integration(数据访问/集成)
JDBC,ORM,OXM,JMS,Transaction
Web
Web,WebSocket,Servlet,Portlet
AOP: 大部分情况下使用动态代理实现,主要负责对面向切面编程的支持,帮助应用对象解耦
Test: 测试模块,使用Spring方便进行测试
Aspects
Instrumentation
Messaging
框架优点
方便解耦,简化开发。pring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理
AOP编程的支持。Spring提供面向切面编程,方便实现对程序进行权限拦截、运行监控等功能
声明式事务的支持。只需要通过配置就可以完成对事务的管理,无需手动编程
方便程序的测试。Spring对Junit4支持,可以通过注解方便的测试Spring程序
方便集成各种优秀框架。Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibernate、MyBatis、Quartz等)的直接支持
降低JavaEE API的使用难度。Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低
IOC/DI(重点)
IOC(inversion of controller)控制反转:对象实例化的权利交由spring容器来管理
本质:xml配置+反射+工厂
使用步骤
xml配置:<bean id|name="名称" class="全类名">
代码中:使用AppliCationContext接口的getBean() 获取对象
DI(dependency injection) 依赖注入:在spring框架负责创建bean对象时,动态将对象的属性值通过配置注入对象中
xml配置:<bean>下添加<property name="类属性名" value="要注入的值">
Bean创建方式
方式一:无参数构造,Bean类中必须提供无参构造,xml配置 <bean>
方式二:静态工厂方法,创建工厂类,在类中提供static返回该类对象的方法即可
xml配置:<bean>添加属性 factory-method="方法名" //通过该方法创建该类的对象
方式三:实例工厂方法,创建工厂类,在类中提供非static返回该类对象的方法即可
xml配置:再配置一个<bean name="" factory-bean="上面bean的name" factory-method="方法名">
Bean作用域
xml配置:<bean>添加属性 scope="singleton|prototype|request|session"
singleton 单例(默认),代表带spring容器中只有一个Bean实例
prototype 多例(常用),每次从spring容器总获取时,都会返回一个新实例
request 用在web开发,将bean对象request.setAttribute()存储到request域中
session ...
Bean的生命周期
1.对象实例化
2.封装属性
3.如果实现BeanNameAware 执行setBeanName
4.如果实现BeanFactoryAwar或ApplicationContextAwar设置工厂setBeanFactory或上下文对象setApplicationContext
5.如果存在类实现BeanPostProcessor(后处理Bean),执行postProcessBeforeInitialization
6.如果实现InitializingBean执行afterPropertiesSet
7.调用自定义的init-method方法
8.如果存在类实现BeanPostProcessor(处理Bean),执行postProcessAfterInitialization
9.执行业务处理
10.如果实现DisposableBean执行destroy
11.调用自定义的destroy-method
第5,第8,可以对Bean的功能增强
第6,第10,完成init与destroy操作。可以使用第7,第11完成,无耦合,推荐使用,需配置
<bean>中添加属性 init-method="方法" destroy-method="方法"(销毁只对单例的有效)
Bean的属性注入方式
方式一:构造器注入,Bean需有对应构造方法
<bean><constructor-arg index="0" type="java数据类型" value="值"></constructor-arg>
方式二:set方法注入,Bean需提供set方法
<bean><property name="属性名" value="值"|ref="其他Bean" />
//集合属性注入
<property name="属性名">下添加
<list><value>值</value><ref bean="其他bean"></list> //list集合|数组注入,数组只能是一种类型
<set>...</set>
<map><entry key="key" value="value"></entry></map> //如果引用类型可以使用 key-ref/value-ref 属性
<props><prop key="key">值</prop></props> //Properties属性注入
//名称空间p和c使用,作用简化属性注入写法(spring2.0后)
它们是虚拟的名称空间,嵌入在spring内核中。
需在xml中,添加p|c名称空间:xmlns:p|c=".../schema/p|c"
c:构造器属性注入 p:set方法注入
简化写法:在<bean>中添加属性 c|p:属性名="值" 或者引用其他bean c|p:属性名-ref="其他bean"
//SpEl(spring expression language),使用表达式完成对属性存储和方法调用
格式: #{表达式}
表达式可以为:其他bean (完成bean之间属性注入),其他bean.属性,其他bean.方法(),加减等操作
xml开发
创建spring配置文件,src/applicationContext.xml
约束:spring-framework-4.2.4.RELEASE\docs\spring-framework-reference\html\xsd-configuration.html
配置要初始化的类
<bean id="名称" class="全类名">
<property name="类属性名" value="要注入的值" > //依赖注入
factory-method="方法名" //静态工厂方法实例化
<constructor-arg index="0" type="java数据类型" value="值"></constructor-arg> //构造器属性注入
<property name="属性名" value="值"|ref="其他Bean" /> //set方法属性注入
<bean name="" factory-bean="上面bean的name" factory-method="方法名"> //实例化方式
</bean>
引入外部属性文件
<context:property-placeholder location="classpath:文件名.properties" />
对于属性文件中的键值对通过 ${键} 获取
连接池配置:
//xml配置连接池
1.使用内置连接池DriverManagerDataSource
driverClassName,url,username,password
配置bean:org.springframework.jdbc.datasource.DriverManagerDataSource
并且注入属性
2.对于第三方连接池,同上使用响应的类和响应属性注入即可
c3p0:com.mchange.v2.c3p0.ComboPooledDataSource,driverClass,jdbcUrl,user,password
开启注解扫描
<context:component-scan base-package="com.service,com.dao">
注解开发
1.配置xml
引入名称空间
xmlns:context=".../context"
xsi中添加: .../schema/context .../schema/context/spring-context.xsd
添加 <context:component-scan base-package="com.service,com.dao">
代表可以使用spring注解,并告诉spring要扫描的包及其子包,多个逗号分隔,
2.导入jar包 spring-aop... (spring3可以不导)
bean注册
类上
@Component("name") //开发中括号不写
//spring2.5后添加三个注解,用于三层架构
@Repository 用于dao层
@Service 用于service层
@Controller 用于web层
//其他
@Scope("prototype") 描述bean的作用域,也可写:ConfigurableBeanFactory.SCOPE_PROTOTYPE
属性上(不需要提供set方法)或set方法上,依赖注入
@Value("值") //简单属性注入
@AutoWired //复杂属性注入,默认根据类型注入
如果根据名称来注入: 再加@Qualifier("其他bean") 或者 换成@Resource(name="其他Bean")
方法上
@PostConstruct //相当于init-method="myInit"
@PreDestroy //相当于destroy-method="myDestroy",只对scope=singleton有效
spring整合junit4测试
导入jar包 spring-test...
测试类上添加注解
@RunWith(SpringJUnit4ClassRunner.class) //spring整合junit4
@ContextConfiguration(locations={"classpath:applicationContext.xml",...}) //指spring配置文件位置
AOP面向切面编程
AOP(Aspect Oriented Programming) 面向切面编程,底层动态代理实现
作用:使得业务逻辑各部分之间的耦合度降低,提高程序可重用性,提高开发效率
应用场景:日志记录,性能统计,事务处理,安全控制,异常处理
OOP 面向对象编程
OOD 面向对象设计
AOP相关术语
目标对象target:被代理对象
切入点pointcut:表示一组连接点,通过判断指定要增强的一些方法
通知advice:(增强)进入到切入点后对该方法的增强操作
切面aspect:切入点和通知的结合
代理对象proxy:被增强后的对象
连接点join poing:指可能被增强的方法
织入weaving:是将切面应用到目标对象从而创建出AOP代理对象的过程
AOP底层实现
静态织入,AspectJ实现,将切面代码直接编译到java类文件中
动态织入,将切面代码进行动态织入实现(spring采用,技术为:jdk动态代理 和 CGLIB动态字节码增强技术)
spring采用动态机制:如果目标对象有接口,优先使用jdk动态代理,无接口,使用cglib动态代理。
JDK动态代理:在JVM内部动态生成class字节码对象(Class对象)
只针对于实现接口的类代理
使用类:Proxy.newProxyInstance(目标对象加载器对象,目标对象实现的接口Class[],InvocationHandler)
CGLIB动态代理:(Code Generation Library)开源项目,底层是使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类
单独使用需导入cglib和asm相关jar包,spring已集成
也可以为没有实现接口的类代理
使用:
Enhancer enhance=new Enhancer(); //创建代理对象
enhance.setSuperclass(目标对象.getClass()); //传递目标对象的Class
enhance.setCallback(MethodInterceptor接口); //设置回调操作,参数是Callback类型,我们使用的是MethodInterceptor接口
基于spring传统AOP编程
支持增强advice的通知类型有5种:
1.前置通知 org.springframework.aop.MethodBeforeAdvice 方法before
2.后置通知 org.springframework.aop.AfterReturningAdvice 方法afterReturning
3.环绕通知 org.aopalliance.intercept.MethodInterceptor
方法invoke 参数MethodInvocation.proceed() //执行目标方法
4.异常通知 org.springframework.aop.ThrowsAdvice
5.引介通知
【方式一】经典基于代理的AOP开发
导入基本jar包和aop联盟依赖jar包 aopalliance.jar
编写目标类target
编写增强类advice
xml中配置:配置目标target的bean,配置通知advice的bean
//定义切点,配置要增强目标对象的哪个方法
<bean id="xPointCut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedNames"><list><value>要增强的方法名</value></list></property>
</bean>
//定义切面aspect=pointcut+advice,将通知和切点绑定
<bean id="xAspect" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="通知引用"/>
<property name="pointcut" ref="切点引用"/>
</bean>
//spring自动配置代理proxy,通过代理对象和切面绑定,调用代理对象即对方法进行增强
<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"></bean>
【方式二】基于aspectJ切点传统开发
xml中配置
导入aop声明,导入aspectj的jar包
//使用aop标签 完成切面,切点,代理声明
<aop:config>
<aop:pointcut expression="execution(* 包名.类名|接口名.方法名(..))" id="xPointCut" /> //定义切点
<aop:advisor advice-ref="通知引用" pointcut-ref="切点引用" /> //定义切面
</aop:config>
扩展:espression表达式常用: execution(* 包名.接口名.*(..)) //第一个*表示方法修饰符
spring整合aspectj框架实现的AOP(推荐使用)
AspectJ:第三方框架,spring只支持部分语法
AspectJ框架定义的通知类型有6种
1.前置通知 Before
2.后置通知 AfterReturning
3.环绕通知 Around
4.抛出通知 AfterThrowing
5.引介通知 DeclareParents
6.最终通知After 不管是否异常,该通知都会执行
【方式三】基于xml开发配置
导入基本jar包和aop联盟依赖jar包 aopalliance.jar
创建目标类
创建通知advice,在aspectj中的通知类可以不实现任何接口,只需定义功能方法即可
xml配置:配置目标对象和advice的bean
//配置代理对象
<aop:config proxy-target-class="true"> //默认false使用jdk动态代理,true使用cglib动态代理
<aop:aspect ref="通知引用"> //定义切面
<aop:pointcut expression="execution(...)" id="xPointCut"/> //定义切点
<aop:before method="通知类方法名" pointcut-ref="切点引用"/> //前置通知
before 前置通知,通知类方法中参数:JoinPoint
getSignature().getDeclaringTypeName() //拦截目标类
getSignature().getName() //拦截方法名称
after-returning 后置通知,参数:JoinPoint,Object获取目标方法返回值。添加:returning="参数名"
around 环绕通知,参数:ProceedingJoinPoint,proceed()执行目标方法
after-throwing 异常通知,参数:JoinPoint,Throwable。添加:throwing="参数名"
after 最终通知,参数:JoinPoint
</aop:aspect>
</aop:config>
【方式四】基于注解开发配置
注解配置目标和通知类的bean
xml配置
配置扫描注解:<context:component-scan base-package="包名"></context:component-scan>
配置代理类:<aop:aspectj-autoproxy proxy-target-class="true"/> //开启aspectj注解自动代理
//通知类advice注解
类上:@Aspect 声明当前bean就是一个切面
方法上:@Before("execution(...)") 声明该方法为前置通知
@AfterReturning(value="execution(...)",returning="参数名") 后置通知
@Around("execution(...)") 环绕通知
@AfterThrowing(value="execution(...)",throwing="参数名")
@After("execution(...)") 最终通知
jdbcTemplate
jdbc Template:jdbc模板,用于操作数据库
使用:导入基本jar包,导入jdbc、txt(事务)的jar包,导入相关数据库驱动jar包
JdbcTemplate的api
setDataSource(DataSource) //设置连接池
//insert、update、delete
update("sql占位?",参数...)
//select
T queryForObject("sql",T.class,参数...) //返回一条数据一个值
T queryForObject("sql",RowMapper<T>,参数...) //复杂查询,返回一条数据,RowMapper中手动封装数据
List<T> query("sql",RowMapper<T>,参数...) //查询返回多条数据
使用RowMapper的实现类BeanPropertyRowMapper<T>(T.class)可以实现数据自动封装
前提:实体类需提供无参public构造,bean属性名称要与表列名对应
如果代码中用到JdbcTemplate,需配置:
//jTemplate的bean配置连接池bean的引用://等价于jTemplate.setDataSource(dataSource);
<bean id="jTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="连接池引用"></property>
</bean>
事务管理 Spring事务管理4个优点
1.提供一致的对于不同的事务管理的API
2.支持声名式事务管理(重点)
3.编程事务管理
4.优秀的整合与spring的数据访问
事务管理机制
【1】org.springframework.transaction.PlatformTransactionManager
平台事务管理器,在不同的持久化层解决技术的事务代码不一样
实现类:
DataSourceTransactionManager 针对于JdbcTemplate开发,MyBatis开发
HibernateTransactionManasger 针对于Hibernate开发
JpaTransactionManager 针对于JPA开发,过时
【2】TransactionDefinition 定义事务的相关信息
隔离:
ISOLATION_DEFUALT 它使用后端数据库的默认隔离级别(spring中选项)
ISOLATION_READ_UNCOMMITTED 不能解决问题,会发生脏读 不可重复读 虚读
ISOLATION_READ_COMMITTED 可以解决脏读(Oracle默认)
ISOLATION_REPEATABLE_READ 可以解决脏读,不可重复读(MySQL默认)
ISOLATION_SERIALIZABLE 串行化,可以解决所有问题
超时 TIMEOUT_DEFAULT 默认-1,使用数据库默认超时时间
只读 值为 true/false,如果为true则只能操作select
传播 解决两个被事务管理的方法互相调用的问题。与数据库无关,是程序内部维护的问题
PROPAGATION_REQUIRED 默认,两个操作处于同一个事务,如果之前没有事务,新建一个事务
PROPAGATION_REQUIRES_NEW 两个操作处于不同的事务
PROPAGATION_NESTED 嵌套事务,使用SavePoint来实现。事务回滚时可以回滚到指定的savepoint,注意:只对DataSourceTransactionManager有作用
以下了解
PROPAGATION_SUPPORTS 支持当前事务,如果不存在,就不使用事务
PROPAGATION_MANDATORY 支持当前事务,如果不存在,抛出异常
PROPAGATION_NOT_SUPPORTED 以非事务运行,如果有事务存在,挂起当前事务
PROPAGATION_NEVER 以非事务运行,如果有事务存在,抛出异常
【3】TransactionStatus 定义了事务状态信息,在事务运行过程中,得到某个时间点的状态
声名式事务管理
事务管理方式
1.编码方案:不建议使用,具有侵入性。因为在原有的业务代码基础上添加事务管理代码
2.声名式事务控制:基于AOP对目标进行代理,添加around环绕通知
基于xml声明式事务管理
spring提供的advice是传统的spring advice
xml配置:
//基本配置,配置这些才可以操作数据库
添加aop与tx名称空间
配置service(目标对象)
配置dao(),注入 dataSource=连接池引用
前提:让dao类去继承JdbcDaoSupport类,使用父类中getJdbcTemplate()获取JdbcTemplate
原因:JdbcDaoSupport类中创建了JdbcTemplate,所以无需我们手动创建JdbcTemplate,配置JdbcTemplate类的对象
//以下配置,完成声名式事务管理,对service方法增强
配置事务管理器 org.springframework.jdbc.datasource.DataSourceTransactionManager
注入 dataSource=连接池引用
配置通知,可以使用spring提供的TransactionInterceptor来完成增强
对于这个增强,使用:
<tx:advice id="" transaction-manager="事务管理器引用">
<tx:attributes>
<tx:method name="account" /> <!-- 代表对account方法进行事务管理 -->
</tx:attributes>
</tx:advice>
//<tx:method>属性介绍:
name:必须写,对哪些方法进行事务控制
isolation 可选 设置事务隔离级别 默认是DEFAULT
propagation:可选 设置事务传播 默认值 REQUIRED
timeout 可选 超时时间 默认值-1
read-only 可选 默认值是false,设置是否只读
rollback-for 可选 可以设置一个异常,如果产生这个异常,触发事务回滚
no-rolback-for 可选 可以设置一个异常,如果产生这个异常,不会触发事务回滚
配置切面,因为使用的传统aop编程,所以使用:
<aop:config>
<aop:pointcut expression="execution(* 包名.类名|接口名.方法名(..))" id="xPointcut"/>
<aop:advisor advice-ref="通知引用" pointcut-ref="切点引用"/>
</aop:config>
基于annotation声明式事务管理方案
在被增强service类上(或方法上,类上相当于对每个方法都声明)添加声名式事务管理注解
@Transactional
在xml中配置开启注解事务控制:代替通知配置,切面配置
<tx:annotation-driven transaction-manager="transactionManager"/>
xml方式与annotation方式的优缺点?
1.从简单上来说,使用注解更方便。
2.使用配置的方案,可以对事务配置进行集中维护
SSH框架整合 SSH:struts2、spring、hibernate
第一步:导入jar包和配置文件
导入struts2的基础jar包,和 struts2-spring-plugin.jar
如果使用struts2提供的json处理:struts2-json-plugin.jar
如果使用注解:struts2-convention-plugin.jar
配置文件:src/struts.xml
导入hibernate的必须jar包
导入c3p0连接池:/hibernate/lib/optional/c3p0/*
导入相关数据库驱动包
导入日志相关jar包
如果使用关于jpa相关操作:hibernate-entitymanager.jar
配置文件:src/hibernate.cfg.xml ,在domain有 xxx.hbm.xml
关于日志:将hibernate/project/etc/log4j.properties文件导入到工程src下
关于数据库连接:xx.properties
导入spring框架基本jar包:beans、context、core、expression
导入aop相关:aop、aopalliance、aspects、aspectjweaver
导入jdbc相关:tx、jdbc
导入commons-loggin jar包
导入整合hibernate:orm
导入整合web:web
如果使用junit测试:junit、spring-test
第二步:在web.xml中
spring整合web,略
配置struts2过滤器,拦截所有:名字:struts2 类:org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
解决no session问题,配置过滤器拦截所有:org.springframework.orm.hibernate5.support.OpenSessionInViewFilter
第三步:ssh整合
------------------xml整合方式-----------------
1.spring整合hibernate
在applicationContext.xml中:
//配置spring提供的LocalSessionFacotry,来管理hibernate的SessionFactory
id=sessionFactory,class=org.springframework.orm.hibernate5.LocalSessionFactoryBean
方式一:零障碍整合(了解)
//加载Hibernate的配置文件,注入属性:
configLocation=classpath:hibernate.cfg.xml
方式二:spring管理hibernate配置文件 //不再需要hibernate.cfg.xml文件,所有关于hibernate的配置都在spring文件中来配置
//加载连接池,注入属性:
dataSource=连接池引用
//配置hibernate的sessionFactory的属性,注入属性
hibernateProperties=<props><prop key="key">value</prop>...</props>
可以简写:<value>key=value 换行... </value>
//加载hibernate的xxx.hbm.xml配置文件,注入属性:
mappingResources=<list><value>cn/domain/User.hbm.xml</value>...</list>
可选其他属性:
mappingJarLocations //加载jar文件中的hbm.xml文件
mappingLocations - classpath:cn/ithiema/domain/User.hbm.xml //它加载时是根据类路径加载 classpath:路径
mappingDirectoryLocations - classpath:cn/itheima/domain //加载的目录
//配置dao,注入属性:
sessionFactory=sessionFactory引用
在dao中:
dao类:继承HibernateDaoSupport类
通过this.getHibernateTemplate()即可获取HibernateTemplate对象
2.spring整合struts2框架
//struts2框架中所有的action,interceptor,result全是bean,在struts2框架中默认是使用strtus2自己bean初化操作(ObjectFactory类)
当在工程中:导入struts2-spring-plugin.jar文件,就会加载这个包下的strtus-plugin.xml文件
这时bean的创建由spring来管理
在action类中:持有业务层,提供set方法
方式一:spring管理action
在xml中:配置action的<bean>,注入业务层类
<bean>声明中添加scope="prototype",原因是struts2框架的action每一次请求都应该是一个新的action
在struts.xml中:配置action,class属性=bean的id值
方式二:action自动装配service(action中自动注入service)//自动装配service方案,这时每一次请求都会新创建一个action
在struts.xml中:配置action,class还是全类名
默认在default.properties中有一段配置:struts.objectFactory.spring.autoWire=name
这时就会将action类中需要注入service主动注入
可以在struts.xml中配置常量:值为 type 时根据类型进行注入
--------------annotation整合方式---------------
在xml中:
1.声明sessionFactory,org.springframework.orm.hibernate5.LocalSessionFactoryBean
注入:dataSource=连接池引用
hibernateProperties=<value>key=value 空格...</value> //配置hibernate属性
packagesToScan=<list><value>实体类的包</value></list> //加载注解类
2.开启注解扫描
<context:component-scan base-package="com.service,com.dao" />
在PO类中:hibernate使用JAP注解来定义PO类,略
在dao中:
类上:@Repository("xDao"),继承 HibernateDaoSupport
创建setSuperSessionFactory(SessionFactory factory){super.setSessionFactory(factory);}
该方法给父类设置SessionFactory
添加注解:@Autowired @Qualifier("sessionFactory引用")
在service中:
类上:@Service("xService")
持有dao对象,添加注解:@Autowired @Qualifier("xDao引用")
在action中:
类上:@Controller @Scope("prototype")
@Namespace("/") @ParentPackage("struts-default")
持有service对象,添加注解:@Autowired @Qualifier("xService引用")
方法上:@Action(value="结合访问路径",results={@Result(name="与返回值匹配"),location="访问路径"})
|