《Spring 开发指南》 台湾知名专家夏昕编写,以前在图书馆偶尔翻阅过,今天得到这本电子书,感觉还是蛮不错的,虽然讲的比较浅,没有深入浅出Hibernate讲的那么深,但在工作中使用还是绰绰有余的。
一 控制反转IOC(Inversion of Control) 也叫依赖注入(Dependence Injection)是由容器控制控制程序之间的关系而非由代码直接控制
二 注入方法:
(1)、接口注入
doGet(HttpServletRequest request,HttpServletResponse response){}
其中HttpServletRequest和HttpServletResponses实例是由Servlet Container容器在运行时动态注入,(依赖关系是在运行时建立的,将调用者和实现者在编译时分离).
(2)、设置注入
通过Setter 和getter方法来注入(常用)
(3)、构造子注入
public class DIConstructor{
private final DataSource dataSource;
private final Stirng message;
public DIConstructor(DataSource dataSource,String message){
this.dataSource=dataSource;
this.message=message;
}
}
依赖关系是通过类的构造函数建立,容器通过调用类的构造函数方法,将其需要的依赖关系注入其中。
四 面向方面AOP(Aspect oriented programmer)
与OOP的区别:OOP可以对雇员进行封装成一个类,并将相应的属性和行为封装其中,是对实体进行封装,而AOP是对业务处理这一切面进行提取。即:OOP面向名字领域,AOP面向动词领域。如”权限检查“这一动作片断。
1)、连接点(JoinPoint) 程序运行到某个阶段点,如:某个方法调用,抛出异常
2)、处理逻辑(Advice) 连接点采用的处理逻辑
Around 在连接点前后插入预处理的过程和后处理的过程
Before 仅仅在连接点之前插入预处理过程
Throw 连接点抛出异常时进行异常处理
3)、切点(PintCut)一系列连接点的集合,它指明处理方式(Advice)将在何时触发,比如事务管理中ops中的prop<prop key="save*"></prop>表明在插入是触发。
五、Spring 基本概念(1) Spring 是轻量级且非侵入性,说它是轻量级的是因为它不依赖容器。说它非侵入性是因为应用独立。不依赖于任何容器。
和EJB的区别:EJB称之为重量级是因为必须要依赖依赖EJB容器。侵入性高,当要把应用单独拿出来时,不容易,因为应用必须依赖容器,离开容器编译都通不过。虽然EJB 也提供事务管理,但必须是EJB组件才可以,而Spring提供声明是事务,只要是普通的对象pojo就可以声明是事务。
(2) 装配依赖关系IOC(Inversion Of Control)控制反转思想。依赖关系不是客户去做,比如创建对象,建立关系。而是交给IOC容器去管理(主动权给了IOC容器)。在配置文件中把所有关系都配好。当一个组件依赖另一个组件时。并且这种关系已经在IOC容器中配置好了,当A需要B时自动会拿到B,自动会把B new好给A,但是A必须提供构造函数,或者必须实行set(A a)方法,把new 好的对象给A。这个就称之为依赖注入DJ(Dependency Injection);DJ是实现依赖关系的一种方法,还有一种叫依赖查找。
ej
public class A{
public save(new B());这个是普通的A依赖B关系,A要使用B。就要请求一对象
}
public class A{
public B b;
(1) 构造方法注入法
public A(B b){
this.b = b;
}
(2) set方法注入法
public void setB(B b){
this.b = b;
}//通过setB();方法,B主动把自己的对象给A,也就是B是主动,A是被动。这就是DJ思想。
}
(3) AOP 比如Filter思想,对方法在执行前做什么,执行后做什么,抛异常做什么
(4) 与其它框架的集成。比如:Struts Hibernate。提供Session和事务管理。而使客户只关心业务就可以了。其它事情都不用担心。
六:applicationContext.xml文件的编写
<beans>
<!-- 普通bean --->
<bean id="bean1" class=""/>
<bean id="bean2" class=""/>
<!-- 引用bean -->
<bean id="bean3" class="" ref="bean1">
或者 bean3 依赖两个bean3和bean4
<bean id="bean3" class="">
<property name="bean3Impl" ref="bean3"/>
<property name="bean4Impl" ref="bean4"/>
</bean>
<!-- 公共属性的bean-->
<bean id="bean4" class="" abstract="true">
<property name="name" value="chen"/>
<property name="password" value="123"/>
</bean>
<bean id="bean5" class="" parent="bean4">
<property name="age" value="98"/>
</bean>
<!-- array,list,set-->
<bean id="bean6" class="">
<list>
<value>123</value>
<value>345</value>
</list>
</bean>
<!-- map -->
<bean id="bean7" class="">
<map>
<entry key="key1" value="value1"/>
<entry key="key2" value="value2"/>
</map>
</bean>
</beans>
BeanFactory 加载applicationContext.xml并且从IOC容器得到bean
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
BeanFactory factory = new ClassPathXmlApplicationContext("applicationContext.xml");
UserManagerImpl userManager = (UserManagerImpl)factory.getBean("userManager");
userManager.save();
七:spring 的作用域
在默认情况下,如果多次调用bean,他们是相等的。它的作用域是singleton,如果把它设置为prototype,每次调用getBean()会产生不同的对象,它们是不等的。
<bean id="" class="" abstract="true" scope="prototype"
八:spring 的装配方式(1) byName
如果一个bean 引用了多个bean配置文件如下
如:bean1引用了bean2 bean3 bean4
<bean id="bean1" class="">
<property name="bean2" ref="bean1"/>
<property name="bean3" ref="bean2"/>
<property name="bean4" ref="bean3"/>
</bean>
如果通过byName(在配置文件beans头部加上<beans default-autowire="byName") 去自动装配,则可以大大简化配置文件
<bean id="bean1" class=""/>这样,在Bean1中包含bean2 bean3 bean4 属性并且有setBean2() setBean3() setBean4()方法,spring会自动查找名字为bean2 bean3 bean4
的bean的定义,并且自动装配上。
(2) byType
就是bean在引用多个bean的时候自动根据类型去查找,而忽视了名字。(在配置文件beans头部加上<beans default-autowire="byType")
如 bean1 有三个属性
private Bean2 bean2 属于cn.com.chenlly.Bean2
private Bean3 bean3 属于cn.com.chenlly.Bean3
private Bean4 bean4 属于cn.com.chenlly.Bean4
而在配置文件中,因为class=""已经指定了所属类。所以自动会根据class类型去装配,而忽视了名字,所以id="bean2" 或者id="bean22" 都无关紧要。ioc容器都会把他们查找到的。
<bean id="bean2" class="cn.com.chenlly.Bean2"/>
<bean id="bean3" class="cn.com.chenlly.Bean3"/>
<bean id="bean4" class="cn.com.chenlly.Bean4"/>
九:AOP 静态代理和动态代理
声明式服务能力
proxy 可以控制原对象,但不能修改原对象。代理类必须和原来的接口(目标类)是一样的不能改变的
典型的横切逻辑应用:比如在调用原对象之前进行安全性检查。
代理模式有两种:静态代理和动态代理。动态代理即AOP思想。下面给出静态代理的例子
UserManager 接口:
public interface UserManager{
public void addUser(String name,String passwrod);
public void deleteUser(int id);
public void modifyUsr(int id);
}
UserManagerImpl 类(目标类)
public class UserManagerImpl implements UserManager{
public void addUser(String name,String passwrod){
//todo something
}
public void deleteUser(int id){
//todo something
}
public void modifyUsr(int id){
//todo something
}
}
UserManagerProxyImpl 代理类
public class UserManagerProxyImpl implements UserManager{
private UserManagerImpl userManagerImpl;
public UserManagerProxyImpl(UserManagerImpl userManagerImpl){
this.userManagerImpl=userManagerImpl;
}
//必须和目标类有一样的实现
public void addUser(String name,String passwrod){
(1)安全性检查
this.checkSecurity();
(2)增加姓名
this.userManagerImpl.addUser(name,password);
}
public void deleteUser(int id){
(1)安全性检查
this.checkSecurity();
(2)删除用户
this.userManagerImpl.deleteUser(id);
}
public void modifyUsr(int id){
(1)安全性检查
this.checkSecurity();
(2)修改用户
this.userManagerImpl.modifyUser(id);
}
//安全性检查
private void checkSecurity(){
//todo something
}
}
这样只要客户端做增加,删除,修改都会增加一个安全性检查的功能。但是静态代理有个缺点就是检验安全性方法遍布整个代理类当中。所以引入了动态代理的思想
把连接点放在一个类里(模块化),当在运行期的时候,把这个方法自动切入。
下面给出动态代理的例子
把要进行安全性检查的方一个法模块化,写在类里。当我们生产了代理对象的时候,如果调用代理方法的时候,
会自动默认调用invoke方法。这个模块化的类就是所谓的切面(Aspect),安全性检查就是advice,
import java.lang.reflect.InvocationHandler;//是代理实例的调用处理程序 实现的接口。
import java.lang.reflect.Proxy;//
public class SecurityHandler implements InvocationHandler{
private Object targetObject;//目标实例
public Object newProxy(Object targetObject){
this.targetObject = targetObject;
//返回一个目标对象的代理类
return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),//目标程序的类加载器
targetObject.getClass().interfaces(),//目标程序的接口
this);//代理指定调用的处理程序
}
public Object invoke(Object proxy,Method method,Object args) throws Throws{
//安全性检查,这是一个before Advice
checkSecurity();
//调用目标对象的正是实现,有可能有返回值,
Object res = null;
try{
res = method.invoke(targetObject,args);
}catch(Exception ex){
ex.printStackTrace();
}
}
//安全性检查
private void checkSecurity(){
//todo something;
}
}
//客户端调用
public class Client{
SecurityHandler sh = new SecurityHandler();
//得到代理类,Annotation就是使用了动态代理机制
UserManagerImpl userManagerImpl = (UserManagerImpl)sh.newProxy(new UserManagerImpl());
userManagerImpl.addUser();
userManagerImpl.deleteUser(12);
}
十:Spring和Hibernate 的事务集成
Spring 配置文件
<!-- 配置SessionFactory-->
<bean id="sessionFactory" class="org.springframwork.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocal">
<value> classpath:/hibernate.cfg.xml</value>
</property>
</bean>
<!--配置事务管理器-->
<bean id="sessionManager" class="org.spring.orm.hibernate3.HibernateTransactionManager"
<property name="sessionFactory" ref="sessionFactory">
</bean>
<!--配置事务的传播性-->
<bean id="baseTxService"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean"
abstract="true">
<property name="transactionManager" ref="transactionManager" />
<property name="proxyTargetClass" value="true" />
<property name="transactionAttributes">
<props>
<prop key="get*">PROPAGATION_REQUIRED,readOnly</prop><!-- 只读事务-->
<prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="load*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="show*">PROPAGATION_REQUIRED,readOnly</prop>
<prop key="save*">PROPAGATION_REQUIRED</prop>
<prop key="update*">PROPAGATION_REQUIRED</prop>
<prop key="remove*">PROPAGATION_REQUIRED</prop>
<prop key="delete*">PROPAGATION_REQUIRED</prop>
<prop key="execute">PROPAGATION_REQUIRED</prop>
</props>
</property>
</bean>
在service 层加事务
<bean id="contractManagerimpl" parent="baseTxService">
<property name="target">
<bean class="com.ngtc.contract.service.impl.ContractManagerImpl" autowire="byName"></bean>
</property>
</bean>
十一、spring 和 Struts 的集成。 Struts 的Action 通过请求path来找type定义的Action,如果没有就创建,如果有从map里取。
通过Spring集成的Struts Action是通过ActionProxy来拿到BeanFactory 和从IOC容器中取的
type里对于的Action,不过在配置Action的配置文件是,name="/xxx" 必须和struts里的path
必须一样。如
struts配置文件
<action path="/login"
type="org.springframework.web.struts.DelegationActionProxy"//是一个代理Action 主要是取的BeanFactory,然后根据<action>中的path属性值到IOC容器中去得到本次请求对应的Action
name="loginForm"
scope="request
>
<forward name="success" path="/success.jsp">
</acton>
spring 配置文件
<bean name="/login" class="cn.com.chenlly.LoginAction">
<property name="" ref="">//注入业务逻辑对象
</bean>