??xml version="1.0" encoding="utf-8" standalone="yes"?>
struts
控制用的
hibernate
操作数据库的
spring
用解耦的
详细的说Q?/span>
STRUTS
?/span>
SSH
框架中v控制的作?/span>
,
其核心是
Controller,
?/span>
ActionServlet,
?/span>
ActionServlet
的核心就?/span>
Struts-confi g.xml.
主要控制逻辑关系的处?/span>
.
hibernate
是数据持久化?/span>
,
是一U新的对象、关pȝ映射工具
,
提供了从
Java
cd数据表的映射Q也提供了数据查询和恢复{机?/span>
,
大大减少数据讉K的复杂度。把Ҏ据库的直接操?/span>
,
转换为对持久对象的操?/span>
.
Struts
?/span>
spring
?/span>
Hibernate
在各层的作用
1
Q?/span>
struts
负责
web
?/span>
.
ActionFormBean
接收|页中表单提交的数据Q然后通过
Action
q行处理Q再
Forward
到对应的|页?/span>
?/span>
struts-config.xml
中定?/span>
<action-mapping>, ActionServlet
会加载?/span>
2
Q?/span>
spring
负责业务层管理,?/span>
Service
Q或
Manager).
1
Q?/span>
service
?/span>
action
提供l计的调用接口,装持久层的
DAO.
2
Q可以写一些自q业务Ҏ?/span>
3
Q统一?/span>
javabean
理Ҏ
4
Q声明式事务理
5.
集成
Hiberante
3
Q?/span>
Hiberante
Q负责持久化层,完成数据库的
crud
操作
hibernate
为持久层Q提?/span>
OR/Mapping
?/span>
它有一l?/span>
.hbm.xml
文g?/span>
POJO,
是跟数据库中的表相对应的。然后定?/span>
DAO
Q这些是跟数据库打交道的c,它们会?/span>
PO
?/span>
?/span>
struts+spring+hibernate
的系l中Q?/span>
对象的调用流E是Q?/span>
jsp-> Action
Q?/span>
> Service ->DAO ->Hibernate
?/span>
数据的流向是
ActionFormBean
接受用户的数据,
Action
数据从
ActionFromBean
中取出,装?/span>
VO
?/span>
PO,
再调用业务层?/span>
Bean
c,完成各种业务处理后再
forward
。而业务层
Bean
收到q个
PO
对象之后Q会调用
DAO
接口ҎQ进行持久化操作?/span>
控制反{(Ioc)
控制反{QIOCQ模?又称DIQDependency Injection)是Inversion of ControlQ控制反转。在Java开发中QIoC意味着你设计好的cMl系l去控制Q而不是在你的cd部控制。这UCؓ控制反{?/p>
IoC(Inversion of Control)是近q来兴v的一U思想Q不仅仅是编E思想。主要是协调各组仉怺的依赖关p,同时大大提高了组件的可移植性,lg的重用机会也变得更多。在传统的实CQ由E序内部代码来控制程序之间的关系。我们经怋用new关键字来实现两组键间关系的组合,q种实现的方式会造成lg之间耦合(一个好的设计,不但要实C码重用,q要组仉关系解?。IoC很好的解决了该问题,它将实现lg间关pME序内部提到外部容器来管理。也是说由容器在运行期组仉的某U依赖关pd态的注入lg中。控制程序间关系的实Cl了外部的容器来完成。即常说的好莱坞原则“Don't call us, we'll call you”?
Ioc也有UCؓDI(Dependecy Injection 依赖注射)Q由Martin Fowler的一《Inversion of Control Containers and the Dependency Injection pattern》提出?
分离xQ?Separation of Concerns : SOCQ是Ioc模式和AOP产生最原始动力Q通过功能分解可得到关注点Q这些关注可以是 lgComponents, 斚wAspects或服务Services?/p>
从GOF设计模式中,我们已经习惯一U思维~程方式QInterface Driven Design 接口驱动Q接口驱动有很多好处Q可以提供不同灵zȝ子类实现Q增加代码稳定和健壮性等{,但是接口一定是需要实现的Q也是如下语句q早要执行:
AInterface a = new AInterfaceImp();
AInterfaceImp是接口AInterface的一个子c,Ioc模式可以延缓接口的实玎ͼҎ需要实玎ͼ有个比喻Q接口如同空的模型套Q在必要Ӟ需要向模型套注石膏,q样才能成ؓ一个模型实体,因此Q我们将Zؓ控制接口的实现成为“注”?/p>
Ioc英文?Inversion of ControlQ即反{模式Q这里有著名的好莱坞理论Q你呆着别动Q到时我会找你?/p>
其实Ioc模式也是解决调用者和被调用者之间的一U关p,上述AInterface实现语句表明当前是在调用被调用者AInterfaceImpQ由于被调用者名U写入了调用者的代码中,q生了一个接口实现的原罪Q彼此联p,调用者和被调用者有紧密联系Q在UML中是用依?Dependency 表示?/p>
但是q种依赖在分d注的思维下是不可忍耐的Q必dԌ实现调用者和被调用者解耦,新的Ioc模式 Dependency Injection 模式由此产生了, Dependency Injection模式是依赖注的意思,也就是将依赖先剥,然后在适当时候再注射q入?/p>
一、Ioc模式QDependency Injection模式Q有三种Q?/p>
W一U类?从JNDI或ServiceManager{获得被调用者,q里cMServiceLocator模式?1.EJB/j2ee 2. AvalonQApache的一个复杂用不多的目Q?
W二U类?使用JavaBeans的setterҎ 1. Spring Framework,2.WebWork/XWork
W三U类?在构造方法中实现依赖 1. PicoContainer,2. HiveMind
有过EJB开发经验的人都知道Q每个EJB的调用都需要通过JNDIL到工厂性质的Home接口Q在我的教程EJB是什么章节中Q我也是从依赖和工厂模式角度来阐qEJB的用?/p>
在通常传统情况下,Z实现调用者和被调用者解耦,分离Q一般是通过工厂模式实现的,下面通过比较工厂模式和Ioc模式不同Q加q解Ioc模式?/p>
二、工厂模式和Ioc
假设有两个类B ?CQB作ؓ调用者,C是被调用者,在B代码中存在对C的调用:
java 代码
public class B{
private C comp;
......
}
实现comp实例有两U途径Q单态工厂模式和Ioc?/p>
工厂模式实现如下Q?/p>
java 代码
public class B{
private C comp;
private final static MyFactory myFactory = MyFactory.getInstance();
public B(){
this.comp = myFactory.createInstanceOfC();
}
public void someMethod(){
this.comp.sayHello();
}
......
}
特点Q?/p>
每次q行ӞMyFactory可根据XML配置文g中定义的C子类实现Q通过createInstanceOfC()生成C的具体实例?
使用Ioc依赖性注? Dependency Injection )实现Picocontainer如下QBcd同通常POJOc,如下Q?/p>
java 代码
public class B{
private C comp;
public B(C comp){
this.comp = comp;
}
public void someMethod(){
this.comp.sayHello();
}
......
}
假设C接口/cL有一个具体实现CImpcR当客户端调用BӞ使用下列代码Q?/p>
java 代码
public class client{
public static void main( String[] args ) {
DefaultPicoContainer container = new DefaultPicoContainer();
container.registerComponentImplementation(CImp.class);
container.registerComponentImplementation(B.class);
B b = (B) container.getComponentInstance(B.class);
b.someMethod();
}
}
因此Q当客户端调用BӞ分别使用工厂模式和Ioc有不同的特点和区别:
主要区别体现在Bcȝ代码Q如果用IocQ在BcM码中不需要嵌入Q何工厂模式等的代码,因ؓq些工厂模式其实q是与C有些间接的联p,q样Q用Iocd解耦了B和C之间的联pR?/p>
使用Ioc带来的代hQ需要在客户端或其它某处q行B和C之间联系的组装?/p>
所以,Iocq没有消除B和C之间q样的联p,只是转移了这U联pR?br /> q种联系转移实际也是一U分d注,它的影响巨大Q它提供了AOP实现的可能?/p>
Ioc和AOP
AOP我们已经知道是一U面向切面的~程方式Q由于Ioc解放自由了Bc,而且可以向Bcd现注Ccd体实玎ͼ如果把BcL像成q行时的横向动作Q无疑注入Ccdcd是AOP中的一UAdviceQ如下图Q?/p>
通过下列代码说明如何使用Picocontainer实现AOPQ该例程主要实现是记录logger功能Q通过Picocontainer可以使用单一行,使所有的应用cȝ记录功能ȀzR?/p>
首先~制一个记录接口:
java 代码
public interface Logging {
public void enableLogging(Log log);
}
有一个LogSwitcherc,主要用来Ȁzd体应用中的记录功能:
java 代码
import org.apache.commons.logging.Log;
public class LogSwitcher
{
protected Log m_log;
public void enableLogging(Log log) {
m_log = log;
m_log.info("Logging Enabled");
}
}
一般的普通应用JavaBeans都可以承这个类Q假设PicoUserManager是一个用L理类Q代码如下:
java 代码
public class PicoUserManager extends LogSwitcher
{
..... //用户理功能
}
public class PicoXXXX1Manager extends LogSwitcher
{
..... //业务功能
}
public class PicoXXXX2Manager extends LogSwitcher
{
..... //业务功能
}
注意LogSwitcher中Log实例是由外界赋予的,也就是说卛_被外界注进入,下面看看使用Picocontainer是如何注Log的具体实例的?/p>
java 代码
DefaultPicoContainer container = new DefaultPicoContainer();
container.registerComponentImplementation(PicoUserManager.class);
container.registerComponentImplementation(PicoXXXX1Manager.class);
container.registerComponentImplementation(PicoXXXX2Manager.class);
.....
Logging logging = (Logging) container.getComponentMulticaster();
logging.enableLogging(new SimpleLog("pico"));//Ȁzlog
׃代码可见Q通过使用单一行logging.enableLogging()Ҏ使所有的应用cȝ记录功能ȀzR这是不是类似AOP的advice实现Q?/p>
MQ用Ioc模式Q可以不将来具体实玎ͼ完全在一个抽象层ơ进行描q和技术架构,因此QIoc模式可以为容器、框架之cȝ软g实现提供了具体的实现手段Q属于架构技术中一U重要的模式应用。J道的JdonSD框架也用了Ioc模式?/p>
参考资料:
Inversion of Control Containers and the Dependency Injection pattern
A Brief Introduction to IoC
Ioc容器的革命性优?br />Java企业pȝ架构选择考量
IOC模式的思考和疑问
三、IoC的几U实现类?/p>
(1)Type1接口注入
通常做法是利用接口将调用者与实现者分R?/p>
java 代码
public class Sport {
private InterfaceBall ball; //InterfaceBall是定义的接口
public void init() {
//Basketball实现了InterfaceBall接口
ball = (InterfaceBall) Class.forName("Basketball").newInstance();
}
}
Sportcd~译期依赖于InterfaceBall的实玎ͼZ调用者与实现者分,我们动态生成Basketballcdƈ通了强制cd转换为InterfaceBall。Apache Avalon是一个典型的Type1型IoC容器?/p>
(2)setterҎ注入
在类中暴露setterҎ来实C赖关pR?/p>
java 代码
public class Sport {
private InterfaceBall ball;
public void setBall(InterfaceBall arg) {
ball = arg;
}
}
q种方式对已l习惯了JavaBean的程序员而言Q更昄观。Spring是实现了该cd的轻量容器?/p>
(3)Type3构造子注入
即通过构造方法完成依赖关pR?/p>
java 代码
public class Sport {
private InterfaceBall ball;
public Sport(InterfaceBall arg) {
ball = arg;
}
}
可以看到Q通过cȝ构造方法徏立依赖关pR由于Type3在构造期Ş成了对象的依赖关p,卛_对象的重用变的困难。有些框枉要组件提供一个默认的构造方法,此时׃CType3的局限性。通常所有的参数都是通过构造方法注入的Q当对象间的依赖关系较多Ӟ构造方法就昄比较复杂Q不利于单元试。PicoContainer是实现了Type3依赖注入模式的轻量容器?br />