一、什么是Spring:
Spring是一个开源的控制反转(Inversion of Control , Ioc)和面向切面(AOP)的容器框架,他的主要目得是简化企业开发。
v 控制反转:所谓的控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的,这样控制权就由应用转移到外部容器,控制权的转移就是所谓的控制反转。
v 依赖注入:所谓的依赖注入就是指:在运行期间,有外部容器动态的将依赖对象注入到组件中。
v 什么是“内聚性”、“耦合性”:
n 藕合度指程序模块间存在联系的紧密程度
n 内聚性则是模块内部的相互依赖程度
n 低耦合就是模块之间的关联少,越独立耦合度越低
n 高内聚就是模块的内容针对干的事情少,功能越单一内聚越高
n 低耦合 电脑的主板上的各种插槽,可以连接很多外置的各种各样的设备,不需要做什么只要简单地“插进去” 不管是分工,还模块设计。模块间,联系越少越好。
二、为什么使用Spring?
v 降低组件之间的耦合度,实现软件层之间的解耦
v 可以使用容器提供的众多服务,如:事物管理服务,消息服务等等,当我们使用容器管理事务时,开发人员就不再需要手工控制事物,也不需要处理复杂的事物传播
v Spring容器提供单例模式支持,开发人员不再需要自己编写实现代码
v 容器提供了AOP技术,利用它很容易实现如权限拦截、运行期监控等等功能
v 容器提供了众多铺作类,使用这些类能够加快应用的开发,如:JdbcTemplate、HibernateTemplate.
v Spring对于主流的应用框架提供了集成支持,如:集成Hibernate、JPA、Struts等,这样更便于应用的开发。
三、关于“轻量级”、“重量级”的划分:
划分一个应用是属于轻量级还是属于重量级的,主要是看此应用使用了多少服务
如Spring容器提供了很多的服务,但是其默认并不是打开的,当你需要某种服务时,就得需要声明,如果应用的服务很少,如 只使用Spring中的核心服务,那么此时我们就可以认为Spring是属于轻量级。目前EJB默认是把所有的服务打开的,所以我们说EJB是重量级的。
四、Spring项目的环境搭配以及测试:
导入jar包:必须的两个包(spring.jar,commons-logging.jar)
实例化spring容器的两种方法:
方法一:
在类路径下寻找配置文件来实例化容器
ApplicationContext ctx=new ClassPathXmlAppliationContext(new String[]{"beans.xml"});
方法二:
在文件系统路径下寻找配置文件来实例化容器
ApplicationContext ctx=new FileSystemXmlApplicationContext(new String[]{"d:\\beans.xml"});
五、三种实例化Bean的方式:
1、使用类构造器实例化
<bean id="" class=""/>
2、使用静态工厂方法实例化:
<bean id="" class="静态工厂的包名.类名" factory-method="静态工厂方法"/>
3、使用实例工厂方法实例化:
<bean id="" class="工厂的包名.类名"/>
<bean id="" factory-bean="id" factory-method="工厂中的方法"/>
主意:
在默认情况下,bean交给Spring容器管理后,那么这个bean是个单实例
六、Bean的生命周期:
1、 Bean在什么时候被初始化的?
(1)、Bean的scope=“singleton”时:在容器实例化的时候就会对bean进行初始化 singleton
(2)、Bean的scope="prototype"时:在调用getBean()时才会对bean进行初始化
2、Bean元素的一些属性解析:
<bean id="" class="" scope="singleton" init-method="" destroy-method=""></bean>
- Id:是bean的唯一标识符
- Scope:定义bean的作用域范围
- Init-method:表示当实例化bean对象后执行的一个初始化方法
- destroy-method:当关闭Spring容器时所执行的方法
七、剖析Spring依赖注入的原理:
1、在xml文件配置中,通过在bean节点下进行配置
1.1、使用属性setter方法注入:
- 基本类型对象注入
- 基本数据类型属性的注入
- 集合类型的注入
如:
<bean id="personDaoBean" class="springs.services.imp.PersonDaoBean"/>
<bean id="personImp" class="springs.services.imp.PersonImp" scope="singleton" init-method="init" destroy-method="destroy">
<property name="personDaoBean" ref="personDaoBean"/>
</bean>
System.out.println("使用setter注入list集合");
for(String value:ps.getListTest())
{
System.out.println(value);
}
System.out.println("使用setter注入map集合");
for(String key:ps.getMap().keySet())
{
System.out.println("key:"+key+"------>"+ps.getMap().get(key));
}
System.out.println("使用setter注入set集合");
for(String value:ps.getSetTest())
{
System.out.println(value);
}
System.out.println("使用setter注入properties集合");
for(Object value:ps.getProperties().keySet())
{
System.out.println(value);
}
1.2、通过构造器的方法也可以实现依赖对象及属性的注入
<constructor-arg index="0" type="springs.services.imp.PersonDaoBean" ref="personDao"></constructor-arg>
<constructor-arg index="1" type="java.lang.String" value="小明"></constructor-arg>
2、使用注解方式进行注入:
2.1在Java代码中使用@Autowired或@Resource进行装配,但是我们需要在xml文件中配置以下东西,同时需要导common-annotations.jar:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd" >
<context:annotation-config/>
2.2 、通过在classpath自动扫描方式把组件纳入到Spring容器当中
在beans.xml需配置为:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd" >
<context:annotation-config/>
<context:component-scan base-package="springs.services.imp"/>
@Service用于标注业务层组件、@Controller用于控制层组件(如struts中的action)@Repository用于标注数据访问组件,即DAO组件,而Component泛指各类组件,当组件不好分类时,即可使用 这个注解进行标注。
八、AOP--代理对象:
1、在不使用任何框架的前提下实现代理对象,业务方法执行的权限控制:
1.1、前提条件:如果想使用代理对象就得使用到一个代理类来创建代理对象(Proxy)而且目标对象必须要实现接口
1.2、目的:通过代理对象可以拦截所有业务方法,判断是否有权限,有则执行业务方法,没有权限则不让它执行业务方法
//创建一个目标对象
package aop.test.cn;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理对象
* @author Administrator
*
*/
public class JDBCProxyFactory implements InvocationHandler{
/**
* 定义一个目标对象
*/
private Object targetObject;
//返回代理对象
public Object createProxyInstance(Object targetObject)
{
this.targetObject=targetObject;
//通过Proxy这个类去创建一个代理对象
Object proxyObject=Proxy.newProxyInstance(this.targetObject.getClass().getClassLoader(), this.targetObject.getClass().getInterfaces(), (InvocationHandler) this);
System.out.println("---->"+this.targetObject.getClass().getClassLoader());
return proxyObject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
OperaDB operaDb=(OperaDB)this.targetObject;
Object resoult=null;
if(operaDb.getUserName().equals("admin"))
{
//调用目标对象的方法
resoult=method.invoke(targetObject, args);
}
return resoult;
}
}
1.3、使用CGLIB实现AOP功能与AOP概念解释 目标对象可以不用实现继承接口)
package aop.test.cn;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 使用CGLIB去创建代理对象
* @author Administrator
*
*/
public class CGlibProxyFactory implements MethodInterceptor{
private Object targetObject;
public Object createProxyInstance(Object targetObject)
{
this.targetObject=targetObject;
Enhancer enhancer=new Enhancer();
//为创建的代理对象继承一个基类
enhancer.setSuperclass(this.targetObject.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
//但调用代理对象时 就回调此方法
@Override
public Object intercept(Object proxy, Method method, Object[] args,
MethodProxy methodProxy) throws Throwable {
OperaDB operaDb=(OperaDB)this.targetObject;
Object object=null;
if(operaDb.getUserName().equals("admin"))
{ //调用业务方法
object=methodProxy.invoke(targetObject, args);
}
return object;
}
}
2 、AOP(面向方面编程)的概念:一般使用AOP编程都是用来做权限管理以及运行监控
2.1、Aspect(切面):指横切性关注点的抽象即为切面,他与类相似 ,只是两者的关注点不一样 ,类是对事物体特征的抽象,而切面是横切性关注点的抽象。
2.2、joinpoint(连接点):所谓连接点是指哪些被拦截到的点,在spring中,这些点指的是方法,因为spring只支持方法类型的链接,实际上joinpoint还可以是field或类构造器。
2.3、pointcut(切入点):所谓切入点是我们要对哪些连接点进行拦截的定义。
2.4、Advice(通知):所谓通知是指拦截到连接点之后所要做的事情就是通知,通知分为前置通知、后置通知、异常通知、最终通知、环绕通知。
2.5、Target(目标对象):代理的目标对象
2.6、Weave(织入):指将aspects应用到target对象并导致proxy对象创建的过程称为织入。
2.7、Introduction(引入):在不修改类代码的前提下,Introduction可以在运行期为类动态地添加一些方法或Field.
2.8、Around(环绕):表示在调用业务方法的前一步执行一次,以及在调用业务方法之后再执行一次。
3、使用spring进行面向切面(AOP)编程
3.1 、 需要导入的jar包(aspectjrt.jar、aspectjweaver.jar、cglib-nodep-2.1_3.jar)
3.2、使用注解方式实现AOP编程:
**
* 面向切面类
* @author Administrator
*
*/
@Aspect
public class SpringAOP {
@Pointcut("execution(* aop.test.cn.OperaDB.*(..))")
//execution表示在调用业务方法时进行拦截, 第一个*表示任何的返回值类型
public void anyMethod()//声明一个切入点
{
}
@Before("anyMethod()&&args(name,id)")
public void doAccessCheck(String name,String id)
{
System.out.println("前置通知!!-->"+name+"-->"+id);
}
@AfterReturning(pointcut="anyMethod()",returning="name1")
public void doAfterReturning(String name1)
{
System.out.println("后置通知-->"+name1);
}
@After("anyMethod()")
public void doAfter()
{
System.out.println("最终通知");
}
@AfterThrowing(pointcut="anyMethod()",throwing="e")
public void doThrowException(Exception e)
{
System.out.println("异常通知(例外通知):"+e);
}
@Around("anyMethod()")
public Object doAround(ProceedingJoinPoint pjp) throws Throwable
{ System.out.println("进入方法");
System.out.println("ProceedingJoinPoint:"+pjp.getArgs()[0]+"-->"+pjp.getArgs());
Object result=null;
if(pjp.getArgs()[0].equals("admin"))
{
result= pjp.proceed();
}
System.out.println("退出方法");
return result;
}
}
3.3使用spring配置文件实现AOP编程:
<aop:aspectj-autoproxy/>
<bean id="xmlSpringAOP" class="aop.test.cn.XMLSpringAOP"/>
<bean id="operaDB" class="aop.test.cn.OperaDB"/>
<aop:config>
<aop:aspect id="asp" ref="xmlSpringAOP">
<aop:pointcut expression="execution(* aop.test.cn.OperaDB.*(java.lang.String,..))" id="mycut"/>
<aop:before method="doAccessCheck" pointcut-ref="mycut"/>
<aop:after-returning method="doAfterReturning" pointcut-ref="mycut"/>
<aop:after-throwing method="doThrowException" pointcut-ref="mycut"/>
<aop:after method="doAfter" pointcut-ref="mycut"/>
<aop:around method="doAround" pointcut-ref="mycut"/>
</aop:aspect>
</aop:config>
******************************************************************
package aop.test.cn;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
/**
* 面向切面类
* @author Administrator
*
*/
public class XMLSpringAOP {
public void doAccessCheck()
{
System.out.println("前置通知!!-->");
}
public void doAfterReturning()
{
System.out.println("后置通知-->");
}
public void doAfter()
{
System.out.println("最终通知");
}
public Object doThrowException()
{
throw new RuntimeException("出现了异常信息!!");
}
public Object doAround(ProceedingJoinPoint pjp) throws Throwable
{ System.out.println("进入方法");
Object result=null;
if(pjp.getArgs()[0].equals("admin"))
{
result= pjp.proceed();
}
System.out.println("退出方法");
return result;
}
}
九、Spring+JDBC 整合开发:
1、Spring+JDBC集成开发的步骤:
l 配置数据源
0.1、需要导入两个jar包:commons-dbcp.jar、commons-pool.jar
<!-- 配置数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<!-- 加载驱动 -->
<property name="driverClassName" value="${driverClassName}" />
<!-- 设置数据库的链接地址 -->
<property name="url" value="${url}"></property>
<!-- 数据库用户名 -->
<property name="username" value="${username}" />
<!-- 数据库密码 -->
<property name="password" value="${password}" />
<!-- 连接池启动时的初始值 -->
<property name="initialSize" value="${initialSize}" />
<!-- 连接池的最大 值-->
<property name="maxActive" value="${maxActive}" />
<!-- 最大空闲值 -->
<property name="maxIdle" value="${maxIdle}" />
<!-- 最小空闲值 -->
<property name="minIdle" value="${minIdle}" />
</bean>
<!-- 采用注解方式去配置事物 -->
<bean id="txManager "class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
<!-- 采用@Transaction注解方式使用事物 -->
<tx:annotation-driven transaction-manager="txManager" />
l 配置事物时,需要在XML配置文件中引入用于声明事物的tx命名空间,事物的配置方式有两种,注解方式和基于XML配置方式
2、使用Spring注解方式管理事务与传播行为详解 :
2.1 使用Spring容器提供的事物管理器可以对事物运行期间出现的事物例外(unchecked) ,进行事物回滚,但是默认不会对用户例外(checked)进行回滚
2.2事物传播属性:
REQUIRED:业务方法需要在一个事物中运行,如果方法运行时,已经处在一个事物中,那么加入到该事物,否则为自己创建一个新的事物。
NOT_SUPPORTED:声明方法不需要事物,如果方法没有关联到一个事物,容器是不会为它开启事物,如果方法在一个事物找中被调用,该事物会被挂起来,在方法调用结束后,原先的事物便会恢复执行。
REQUIRESNEW:属性表明不管是否存在事物,业务方法总会为自己发起一个新的事物,如果方法已经运行在一个事物中,则原有事物会被挂起来,新的事物会被创建,直到方法执行结束,新的事物才算结束原先的事物才会回复
MANDATORY:该属性指定业务方法只能在一个已经存在的事物中执行,业务方法不能发起自己的事物,如果业务方法在没有事物的 环境下调用,容器就会抛出异常
SUPPORTS:这一事物属性表明,如果业务方法在某个事物范围内被调用,则方法成为该事物的一部分,如果业务方法在事物范围外被调用,则方法在没有事物环境下执行
Never:指定业务方法绝对不能在事物范围内执行,如果业务方法在某个事物中执行,容器则会抛出异常,只有业务方法没有关联到任何事物,才能正常执行。
NESTED(嵌套):如果一个活动的事物存在,则运行在一个嵌套的事物中,则按REQUIRED属性执行,它使用一个单独的事物,这个事物拥有多个可以回滚的保存点,内部事物的回滚不会对外部事物造成影响,她只对DataSourceTransactionManager事物管理器起效。
3、采用基于XML配置文件实现事物管理:
<aop:config>
<aop:pointcut id="transactionPointCut" expression="execution(* spring.personBean.cn.PersonBean.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="transactionPointCut"/>
</aop:config>
<!-- 事物消息管理 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
<tx:attributes>
<!-- 对于get开头的业务方法不开启事物管理 -->
<tx:method name="get*" read-only="true" propagation="NOT_SUPPORTED"/>
<tx:method name="*"/>
</tx:attributes>
</tx:advice>
4、Spring集成的Hibernate配置二级缓存 :
4.1首先得在beans.xml文件中id为sessionFactory元素的子元素配置如下:
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQL5Dialect
hibernate.hbm2ddl.auto=update
hibernate.show_sql=false
hibernate.format_sql=false
hibernate.cache.use_second_level_cache=true
hibernate.cache.use_query_cache=false
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
</value>
</property>
4.2然后建立一个ehcach.xml文件配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<!--
defaultCache节点为缺省的缓存策略
maxElementsInMemory 内存中最大允许存在的对象数量
eternal 设置缓存中的对象是否永远不过期
overflowToDisk 把溢出的对象存放到硬盘上
timeToIdleSeconds 指定缓存对象空闲多长时间就过期,过期的对象会被清除掉
timeToLiveSeconds 指定缓存对象总的存活时间
diskPersistent 当jvm结束是是否持久化对象
diskExpiryThreadIntervalSeconds 指定专门用于清除过期对象的监听线程的轮询时间
-->
<ehcache>
<diskStore path="D:\cache"/>
<defaultCache maxElementsInMemory="1000" eternal="false" overflowToDisk="true"
timeToIdleSeconds="120"
timeToLiveSeconds="180"
diskPersistent="false"
diskExpiryThreadIntervalSeconds="60"/>
<cache name="ssh.com.bean.Student" maxElementsInMemory="100" eternal="false" overflowToDisk="true" timeToIdleSeconds="300" timeToLiveSeconds="600" diskPersistent="false"/>
</ehcache>
4.3、在映射文件上配置如下信息:
<cache usage="read-write" region="ssh.com.bean.Student"/>
5、 二级缓存的适用范围
Hibernate的二级缓存作为一个可插入的组件在使用的时候也是可以进行配置的,但并不是所有的对象都适合放在二级缓存中。
在通常情况下会将具有以下特征的数据放入到二级缓存中:
● 很少被修改的数据。
● 不是很重要的数据,允许出现偶尔并发的数据。
● 不会被并发访问的数据。
● 参考数据。
而对于具有以下特征的数据则不适合放在二级缓存中:
● 经常被修改的数据。
● 财务数据,绝对不允许出现并发。
● 与其他应用共享的数据。