spring入门基础
以下文字和代码基本摘自Spring in action 第四版
- 一个Spring组件可以是任何形式的POJO
Spring的四种关键策略
- 基于POJO的轻量级和最小侵入性编程
- 通过依赖注入和面向接口实现松耦合
- 基于切面和惯例进行声明式编程
- 通过切面和模板减少样板式代码
依赖注入(Dependency Injection DI)
依赖可理解为与自身对象相互协作的对象,如在自身属性中有对其他对象的引用以及直接的实例化而非参数传递
如
public class Knight{
private Quest quest;
public Knight(){
this.quest = new Quest();//紧耦合
}
public void embarkOnQUest(){
quest.embark();
}
}
通过DI,对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定,
即将所依赖的关系自动交给目标对象,而不是让对象自己去获取依赖
public class Knight{
private Quest quest;
public Knight(Quest quest){
this.quest = quest;//被注入
}
public void embarkOnQUest(){
quest.embark();
}
}
创建应用组件之间协作的行为通常称为装配(wiring),可通过xml和Java代码配置
Java代码配置需要@Configuration注解
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="****" ****>
<bean id="knight" class="包名.类名">
<constructor-arg ref="quest"/> //注入构造器参数
</bean>
<bean id="quest" class="">
***
</bean>
等价于
@Configuration
public class KnightConfig{
@Bean
public Knight knight(){
return new Knight(quest());
}
@Bean
public Quest quest(){
return new Quest();
}
}
Spring 通过应用上下文装载bean的定义并把它们组装起来
上下文的分类
(ApplicationContext接口的实现类)
- AnnotationConfigApplicationContext 从一个或多个基于Java的配置类中加载Spring应用上下文
- AnnotationConfigWebApplicationContext 从一个或多个基于Java的配置类中加载SpringWeb应用上下文
- ClassPathXmlApplicationContext 从类路径下的一个或多个xml配置文件中加载上下文定义,把应用上下文的定义文件作为类资源
- FileSystemXmlApplicationContext 从文件系统下的一个或多个xml配置文件中加载上下文定义
- XmlWebApplicationContext 从web应用下的一个或多个xml配置文件中加载上下文定义
ApplicationContext context = new ClassPathXmlApplicationContext("xml文件路径");
ApplicationContext context = new AnnotationConfigApplicationContext(****.class);
ApplicationContext context = new FileSystemXmlApplicationContext("xml文件绝对路径C:/knight.xml");
Knight knight = context.getBean(Knight.class);
context.close();
切面简单实例
DI 能够让相互协作的组件保持松散耦合,而面向切面编程(aspect-oriented-programming AOP)允许你把遍布应用各处的功能分离出来形成可重用的组件(促使软件系统实现关注点分离)
例如吟游诗人歌颂骑士
public class Minstrel{
private PrintStrean strean;
public Minstrel(PrintStream strean){
this.stream = stream;
}
public void singBeforeQuest(){//探险之前调用
stream.println("the knight is brave");
}
public void singAfterQuest(){//探险之后调用
stream.println("did embark on a quest");
}
}
骑士
public class BraveKnight implement Knight{
private QUest quest;
private Minstrel minstrel;
public BraveKnight(Quest quest,Minstrel minstrel){
this.quest = quest;
this.minstrel = minstrel;
}
public void embarkOnQuest(){
minstrel.singBeforeQuest();
quest.embark();
minstrel.singAfterQuest();
}
}
问题在于管理他的吟游诗人并不是骑士职责范围内的工作,而利用AOP可以声明吟游诗人必须歌颂骑士 而骑士本身并不用直接访问Minstrel的方法。
将Minstrel声明为一个切面
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="****" ****>
<bean id="knight" class="包名.类名">
<constructor-arg ref="quest"/> //注入构造器参数
</bean>
<bean id="quest" class="">
<constructor-arg ref="#{T(System).out}"/>
</bean>
<bean id="minstrel" class="***.Minstrel">
<constructor-arg ref="#{T(System).out}"/>
</bean>
<aop:config>
<aop:aspect ref="minstrel">
<aop:pointcut id="embark"
expression="execution(* *.embarkOnQuest())" /> //定义切点
<aop:breore //声明前置通知 pointcut-ref="embark" method="singBeforeQUest" />
<aop:after //声明后置通知 pointcut-ref="embark" method="singAfterQUest" />
</aop:aspect>
</aop:config>
</beans>