Spring用JavaBean
来表示应用组件,JavaBean
在此处指的是POJO
,即简单老式java对象。
Spring通过以下四个方面简化java开发:
- 基于POJO的轻量级和最小侵入性编程
- 通过依赖注入和面向接口实现松耦合
- 基于切面和惯例进行声明式编程
- 通过切面和模板减少样板式代码
依赖注入:DI 面向切面编程:AOP
Spring不强迫使用接口或类,在Spring应用中通常看不到使用了Spring的痕迹
用依赖注入让对象间松散耦合:
为了摆脱对象间的紧耦合,使用DI,依赖关系将被自动注入到需要他们的对象中。
构造器注入,也就是构造器传入一个大的类的对象,具有该类接口的类就可以传入(注入),不用调用其他对象。使用时用传入的就可以。以书上代码为例,两个类分别为:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| package com.springinaction.knights;
public class BraveKnight implements Knight {
private Quest quest;
public BraveKnight(Quest quest) { this.quest = quest; }
public void embarkOnQuest() { quest.embark(); } }
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| package com.springinaction.knights;
import java.io.PrintStream;
public class SlayDragonQuest implements Quest {
private PrintStream stream;
public SlayDragonQuest(PrintStream stream) { this.stream = stream; }
public void embark() { stream.println("Embarking on quest to slay the dragon!"); } }
|
如果一个对象只通过接口(而不是具体实现或初始化过程)来表明依赖关系,呢么这种依赖就能够在对象本身毫不知情的情况下,用不同的具体实现进行替换。
使用依赖注入需要两个额外文件,一个是表明协作关系的装配文件(xml或java),另一个是应用上下文Main,用来创建和组装对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| <?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">
<bean id="knight" class="com.springinaction.knights.BraveKnight"> <constructor-arg ref="quest" /> </bean>
<bean id="quest" class="com.springinaction.knights.SlayDragonQuest"> <constructor-arg value="#{T(System).out}" /> </bean> </beans>
|
二者都被声明bBean,在这里的BraveKnight在构造时传入了对SlayDragonQuest bean的引用,作为构造器的参数。
疑惑 如果id唯一,怎么实现的不同的依赖注入,一个id可以对应多个class?或者说不同的类用同一个借口进行依赖注入是否必要?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| package com.springinaction.knights;
import org.springframework.context.support. ClassPathXmlApplicationContext;
public class KnightMain {
public static void main(String[] args) throws Exception { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext( "META-INF/spring/knights.xml"); Knight knight = context.getBean(Knight.class); knight.embarkOnQuest(); context.close(); }
}
|
这是基于XML文件创建的应用上下文。调用该应用上下文获得了一个ID为knight的bean,这个类只是用来执行embarkOnQuest()方法,不知道是哪个对象来执行。(这说的还是有点绕啊。。)
面向切片编程,将服务模块化
在实际使用中,有很多服务如安全、日志、事务管理都是所有应用要用到的。面向切片编程(AOP)可以把它们变成切面覆盖在组件上,以声明的方式存在。
骑士不该去管理吟游诗人。吟游诗人该做好自己的事。
在配置文件声明切面:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <bean id="minstrel" class="com.springinaction.knights.Minstrel"> <constructor-arg value="#{T(System).out}" /> </bean>
<aop:config> <aop:aspect ref="minstrel"> <aop:pointcut id="embark" expression="execution(* *.embarkOnQuest(..))"/> <aop:before pointcut-ref="embark" method="singBeforeQuest"/>
<aop:after pointcut-ref="embark" method="singAfterQuest"/> </aop:aspect> </aop:config>
|
先定义一个bean,再aop命名空间定义切点,切点前通知,切点后通知
此外还有通过模块封装来消除样板代码
比如JDBC的样板代码
结语
参考:Spring实战(第四版) 人民邮电出版社
具体的Spring学习在之后更新。(希望如此)
关于配置环境:有了maven后果然简单多了,参照Spring官网:https://spring.io/guides/gs/intellij-idea/
遇到了非常坑的一件事情:我的mavensetting中用了镜像但却在注释里。。。于是怎么都装不上依赖包。
最后附上Spring框架的结构图