简化Spring的java开发
1.1简介
区别于EJB的特性 简化javaBean,为了降低java开发的复杂性,Spring采取了以下4种关键策略:
- 基于POJO的轻量级和最小入侵性编程
- 通过依赖注入和面向接口实现松耦合
- 基于切面和惯例进行声明式编程
- 通过切面和模板减少样板式代码
1.2依赖注入(DI)
依赖注入到底是什么呢?任何一个有实际意义的应用都会由两个或者多个类组成,这些类进行相互协作来完成特定的业务逻辑.按照传统的做法,没个对象负责管理与自己相互协作的对象(即它所依赖的对象)的引用,这将会导致高度耦合和难以测试的代码.
例子:
骑士去探险
/**
* 骑士
*/
public interface Knight {
public void embarkOnQuest();
}
/**
*
* 探险类型
*/
public interface Quest {
public void embark();
}
/**
* 勇敢的骑士
*/
public class BraveKnight implements Knight {
private Quest quest;
//quest被注入进来(构造注入)
public BraveKnight(Quest quest) {
this.quest = quest;
}
public void embarkOnQuest() {
quest.embark();
}
}
这个例子中的Quest是通过构造参数传递进来的,这里的重点是BraveKnight没有与任何特定的Quest实现发生耦合.对于它来说,被要求挑战的探险任务只要实现了Quest接口,那么具体是哪种类型的探险就无关紧要了.这就是DI所带来的最大收益 - - 松耦合.
对依赖进行替换的时候只需要给Quest的接口一个实现类即可
/**
* 任务的实现类
*/
public class QuestImpl implements Quest{
//从事 开始方法
public void embark() {
System.out.println("开始探险");
}
}
/**
* 进行依赖的测试
*/
@Test
public void KinghtShouldEmbarkOnQuest() {
//向上转型
Quest questimpl = (Quest) new QuestImpl();
//注入Quest的实现类QuestImpl
BraveKnight knight = new BraveKnight(questimpl);
//执行方法
knight.embarkOnQuest();
}
1.3通过Spring的Xml进行配置实现
application.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--注入BraveKnight-->
<bean id="braveKnight" class="BraveKnight">
<constructor-arg ref="quest"/>
</bean>
<!--注入QuestImpl-->
<bean id="quest" class="QuestImpl"></bean>
</beans>
进行Spring的测试
public static void main(String[] args) {
//加载配置文件 加载Spring的上下文
ApplicationContext app = new ClassPathXmlApplicationContext("classpath:application.xml");
//获取bean
BraveKnight bean = app.getBean(BraveKnight.class);
//调用方法
bean.embarkOnQuest();
}
1.4应用切面编程(AOP)
上面已经介绍了DI能够让互相协作的软件组织 保持松耦合,而面向切面编程(AOP)允许你把遍布应用各处的功能分离出来形成可重用的组件.
常见的AOP抽离出来的组件有:日志模块;事务模块;安全模块等.
AOP能够让服务模块化,并以声明的方式将他们应用到他们需要影响的组件中去.这样做的好处是可以让这些组件具有更高的内聚性并且更加关注自身的核心业务,完全不需要了解设计系统服务所带来的复杂性,总之,AOP能够确保POJO的简单性. 我们可以把切面想象为覆盖在很多组件之上的一个外壳,如下图所示:
例子:还是以刚才的骑士为例,我们熟知吟游诗人这个服务类会来记载骑士的所有事迹.
主要的类如下:
//吟游诗人作为切面
public class Minstrel {
public void singBeforeQuest(){
//探险之前
System.out.println("Before: Fa la la ,the Knight is so breave!");
}
public void singAfterQuest(){
//探险之后
System.out.println("After: Tee hee hee ,the breave Knight!");
}
}
AOP的XMl配置的实例如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注入BraveKnight-->
<bean id="braveKnight" class="BraveKnight">
<constructor-arg ref="quest"/>
</bean>
<!--注入QuestImpl-->
<bean id="quest" class="QuestImpl"/>
<!--AOP实例-->
<!--注入Minstrel-->
<bean id="minstrel" class="com.aop.Minstrel"/>
<aop:config>
<!--声明切面-->
<aop:aspect ref="minstrel">
<!--定义切点 这里定义的是骑士的方法-->
<aop:pointcut id="embark" expression="execution(* QuestImpl.embark(..))"/>
<!--声明前置通知-->
<aop:before pointcut-ref="embark" method="singBeforeQuest"/>
<!--声明后置通知-->
<aop:after pointcut-ref="embark" method="singAfterQuest"/>
</aop:aspect>
</aop:config>
</beans>
AOP的主要配置涉及到切面和切点,我们先定义横切面的类的Bean并进行注入,然后我们需要相关的类的方法作为切点,AOP的主要用法有:前置通知;后置通知;环绕通知,用于在核心代码前面后面加入相关的切面的代码的实现.