一 开始spring之路
1 spring 版的hello world
(1) 首先创建一个Greeting Service 接口, 将实现从接口中分离出来。
package cn.bupt.duming.service;
public interface GreetingService {
void sayHello() ;
}
(2) GreetingServiceImpl 是GreetingService接口的实现
尽管看起来,在此处没必要隐藏接口,但是我们还是建议将实现与接口分离。
public class GreetingServiceImpl implements GreetingService {
private String greeting ;
public GreetingServiceImpl(){
}
public GreetingServiceImpl(String greeting){
this.greeting = greeting ;
}
public void sayHello() {
System.out.println(greeting);
}
public void setGreeting(String greeting){
this.greeting = greeting ;
}
}
现在的问题是在何处调用上述的set方法,和构造函数。
(3) 在Spring 中配置 HelloWorld.xml
<bean id = "greetingService" class = "cn.bupt.duming.service.GreetingServiceImpl" >
<property name="greeting" value = "hello world"></property>
</bean>
在文件中配置了一个 GreetingServiceImpl的实例 , <property>是设置属性的值, 就是 GreetingServiceImpl
实例中的greeting 的值。
(4) 在Spring 中配置实例的构造函数
<bean id = "greetingService" class = "cn.bupt.duming.service.GreetingServiceImpl" >
<constructor-arg value = "hello world"></constructor-arg>
</bean>
(5)测试类
BeanFactory factory = new XmlBeanFactory(
new FileSystemResource("applicationContext.xml")) ;
GreetingService greetingService = (GreetingService) factory.getBean("greetingService") ;
greetingService.sayHello() ;
这里的BeanFactory就是Spring 容器。
二 依赖注入 DI
1 DI应用
(1) 骑士接口
public interface Knight {
Object embarkOnQuest() ;
}
(2) 圆桌武士Bean
public class KnightOfTheRoundTable implements Knight{
private String name ;
private Quest quest ; //只定义接口实例,这样不光能进行圣杯探险,还能进行其他的探险
public KnightOfTheRoundTable(String name){
this.name = name ;
quest = new HollyGrailQuest() ;
}
public Object embarkOnQuest() {
// TODO Auto-generated method stub
return quest.embark() ;
}
// 这样骑士可以进行各种各样的探险,不一定是圣杯探险
public void setQuest(Quest quest){
this.quest = quest ;
}
(3) 探险接口
public interface Quest {
abstract Object embark() ;
}
(4) 进行圣杯探险
public class HollyGrailQuest implements Quest{
public HollyGrailQuest(){
}
public Object embark() {
// TODO Auto-generated method stub
System.out.println("探险开始");
return new Object();
}
}
以上代码实现与接口相分离,减少了耦合。
(5) 配置文件
在此处配置具体的探险类
<bean id ="quest" class="cn.bupt.duming.di.HollyGrailQuest">
</bean>
// 在此处构造骑士 , 并和相应的探险任务建立关联
<bean id="knight" class = "cn.bupt.duming.di.KnightOfTheRoundTable">
<constructor-arg value="duming"></constructor-arg>
<property name="quest" ref="quest" ></property>
</bean>
(6) 理解DI
Di 只是一种松散耦合的代码,这样尽可以是应用对象之间保持疏远的关系。
三 应用AOP
1 AOP介绍
AOP用来在软件系统中实现业务分离,使用AOP,你可以使各种功能层来覆盖核心业务层。它将安全、事务、
和日志功能与核心业务层相分开。
2 具体应用
我们在上面的骑士的例子中,添加一个日志切面。
(1) 需求
为每一个骑士增加一个诗人相陪伴,用歌曲来记录骑士的功绩和行动。
(2)代码实现
Minstrel实现类
public class Minstrel {
public void singBefore(Knight knight){
System.out.println("sing before");
}
public void singAfter(Knight knight){
System.out.println("singafter");
}
}
//在圆桌骑士类中增添诗人的属性
public class KnightOfTheRoundTable implements Knight{
private String name ;
private Quest quest ;
private Minstrel minstrel ;
public void setMinstrel(Minstrel minstrel) {
this.minstrel = minstrel;
}
public KnightOfTheRoundTable(String name){
this.name = name ;
quest = new HollyGrailQuest() ;
}
public Object embarkOnQuest() {
// TODO Auto-generated method stub
minstrel.singBefore(this) ;
minstrel.singAfter(this) ;
return quest.embark() ;
}
public String getName() {
return name;
}
// 这样骑士可以进行各种各样的探险,不一定是圣杯探险
public void setQuest(Quest quest){
this.quest = quest ;
}
配置文件新增部分如下:
<bean id ="minstrel" class = "cn.bupt.duming.di.Minstrel">
</bean>
<bean id="knight" class = "cn.bupt.duming.di.KnightOfTheRoundTable">
<constructor-arg value="duming"></constructor-arg>
<property name="quest" ref="quest"></property>
<property name="minstrel" ref="minstrel"></property>
</bean>
(3) 缺陷
代码中红色部分显示,每个骑士在继续探险前,必须吩咐诗人谱一首曲子,在探险之后,骑士必须告诉诗人让其歌颂他
得事迹。 理想状态下,骑士应该不用关心诗人,简单的说诗人提供的服务超过了骑士的责任,也就是说诗人的工作和骑士
的工作交织在一起 。所以应该把诗人实现为切面,并把他写歌的服务提供给骑士。
(4)编织切面
配置文件如下:
<aop:config>
<aop:aspect ref="minstrel">
<aop:pointcut id="questPointcut"
expression ="execution(* *.embarkOnQuest(..))
and target(bean)"/>
<aop:before
method="singBefore"
pointcut-ref="questPointcut"
arg-names="beans"
/>
<aop:after-returning
method="singAfter"
pointcut-ref="questPointcut"
arg-names="bean"
/>
</aop:aspect>
</aop:config>
骑士类无需知道诗人的存在,作为一个切面,诗人自动处理歌颂事项。结果骑士恢复到了一个更简单的形式。
public class KnightOfTheRoundTable implements Knight{
private String name ;
private Quest quest ;
public KnightOfTheRoundTable(String name){
this.name = name ;
quest = new HollyGrailQuest() ;
}
public Object embarkOnQuest() {
// TODO Auto-generated method stub
return quest.embark() ;
}
public String getName() {
return name;
}
// 这样骑士可以进行各种各样的探险,不一定是圣杯探险
public void setQuest(Quest quest){
this.quest = quest ;
}
}