Spring实战第一章
一、
1、Spring是如何简化Java开发的?
1、基于POJO的轻量级和最小侵入性的编程
2、通过DI和面向接口实现松耦合
3、基于切面和管理进行声明式编程
4、通过切面和模板减少样板式代码
2、依赖注入(DI)简介
传统中,每个对象负责管理与自己相互协作的对象(即是所依赖的对象)的引用,这样会导致高耦合和难以测试。
通过DI,对象的依赖关系将由系统中负责协调各对象的第三方组件在创建对象的时候进行设定。
构造器依赖注入
braveknight
package com.wang.Frist; public class BraveKnight implements Knight { private Quest quest; @Override public void embarkOnQuest(){ quest.embark(); } public BraveKnight(Quest quest) //通过构造器注入 { this.quest=quest; } }
package com.wang.Frist; import java.io.PrintStream; public class slayDragonquest implements Quest { private PrintStream stream; public slayDragonquest(PrintStream stream){ this.stream = stream; } @Override public void embark(){ // TODO Auto-generated method stub stream.println("Embarking on quest to slay the dragon!"); } }
传统通过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-3.0.xsd"> <bean id="knight" class="com.wang.Frist.BraveKnight"> <constructor-arg ref="quest"/> </bean> <bean id="quest" class="com.wang.Frist.slayDragonquest"> <constructor-arg value="#{T(System).out}" /> </bean> </beans>
使用Java的配置完成的注入
package com.wang.Frist; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @Configuration public class KnightConfig { @Bean public Knight knight(){ return new BraveKnight(quest()); } @Bean public Quest quest(){ return new slayDragonquest(System.out); } }
通过XML或者是基于Java的配置,都实现了DI使其BraveKinght依赖Quest,但是并不知道传递给他的是什么类型。
2.1Spring的应用上下文(Application Context)
Spring通过应用上下文并把他们组装起来,Spring应用上下文全权负责对象的创建和组装。
比如如果bean是通过xml文件进行配置的:
package com.wang.Frist; import org.springframework.context.support.ClassPathXmlApplicationContext; public class KnightMain { public static void main(String[] Args){ ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("kinghts.xml"); Knight knight = context.getBean(Knight.class); knight.embarkOnQuest(); context.close(); } }
3、AOP简介
面向切面编程允许你把遍布应用各处的功能分离出来形成可重用的组件。
面向切面编程往往被定义为促使软件系统实现关注点分离的技术。系统由组件组成,每个组件有其各自负责的一块特定的功能。除了实现自身核心的功能之外,组件还承担着额外的职责,诸如日志这样的系统服务经常融入到自身具有核心业务逻辑的组件之中,这些系统服务通常被称为横切关注点。
AOP能够使得这些服务模块化,并以声明的方式见他们应用到他们需要影响的组件中去。已使得这些组件具有跟高的内聚性和更加关注自身的业务。
设置一个切面
用于记录骑士的行为
package com.wang.Frist; import java.io.PrintStream; public class Minstrel { private PrintStream printStream; public Minstrel(PrintStream printStream){ this.printStream = printStream; } public void singBeforeQuest(){ printStream.println("Fa la la,the knight is so brave"); } public void singAfterQuest(){ printStream.println("Tee hee hee,the brave knight did embark on a quest!"); } }
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-3.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"> <bean id="knight" class="com.wang.Frist.BraveKnight"> <constructor-arg ref="quest"/> </bean> <bean id="quest" class="com.wang.Frist.slayDragonquest"> <constructor-arg value="#{T(System).out}" /> </bean> <bean id="minstrel" class="com.wang.Frist.Minstrel"> <constructor-arg value="#{T(System).out}" /> </bean> <aop:config> <aop:aspect ref="minstrel"> 设置切面 <aop:pointcut expression="execution(* *.embarkOnQuest(..))" id="embark"/> 设置切点 <aop:before pointcut-ref="embark" method="singBeforeQuest"/> 设置执行的顺序 <aop:after pointcut-ref="embark" method="singAfterQuest"/> </aop:aspect> </aop:config> </beans>
测试:
package com.wang.Frist; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class BraveMinsterAop { public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("kinghtAopl.xml"); Knight knight = (Knight) context.getBean("knight"); knight.embarkOnQuest(); } }
这里使用了Spring的aop配置命名空间把Minstrel bean声明为一个切面。首先,需要把Minstrel声明为一个bean,然后 在<aop:aspect>元素中引用该bean。为了进一步定义切面,声明(使用<aop:before>)在embarkOnQuest()方法执行前调 用Minstrel的singBeforeQuest()方法。这种方式被称为前置通知(before advice)。同时声明(使用<aop:after>)
在embarkOnQuest()方法执行后调用singAfter Quest()方法。这种方式被称为后置通知(after advice)。
4、消除样板代码
二、bean容器
在基于Spring的应用中,应用对象生存于Spring容器(container)中。Spring容器负责创建对象,装配它们,配置它们并管理它们的整个生命周期,
从生存到死亡(在这里,可能就是new到finalize())
Spring容器可以归为 两种不同的类型。
1、bean工厂(由org.springframework.beans.factory.beanFactory接口定义)是最简单的容器,提供基本的DI 支持。
2、应用上下文 (由org.springframework.context.ApplicationContext 接口定义)基于BeanFactory构建,并提供应用框架级别的服务,
例如 从属性文件解析文本信息以及发布应用事件给感兴趣的事件监听者。
2.1、应用上下文
AnnotationConfigApplicationContext:从一个或多个基于Java的配置类中加载Spring应用上下文。
AnnotationConfigWebApplicationContext:从一个或多个基于Java的配置类中加载Spring Web应用上下文。
ClassPathXmlApplicationContext:从类路径下的一个或多个XML配置文件中加载上下文定义,把应用上下文的定义文件 作为类资源。
FileSystemXmlapplicationcontext:从文件系统下的一个或多个XML配置文件中加载上下文定义。
XmlWebApplicationContext:从Web应用下的一个或多个XML配置文件中加载上下文定义。
2.2bean的生命周期
图示:
对图描述:
1.Spring对bean进行实例化;
2.Spring将值和bean的引用注入到bean对应的属性中;
3.如果bean实现了BeanNameAware接口,Spring将bean的ID传递给 setBean-Name()方法;
4.如果bean实现了BeanFactoryAware接口,Spring将调 用setBeanFactory()方法,将BeanFactory容器实例传入;
5.如果bean实现了ApplicationContextAware接口,Spring将调 用setApplicationContext()方法,将bean所在的应用上下文的 引用传入进来;
6.如果bean实现了BeanPostProcessor接口,Spring将调用它们 的postProcessBeforeInitialization()方法;
7.如果bean实现了InitializingBean接口,Spring将调用它们的 afterPropertiesSet()方法。类似地,如果bean使用initmethod 声明了初始化方法,该方法也会被调用;
8.如果bean实现了BeanPostProcessor接口,Spring将调用它们 的postProcessAfterInitialization()方法;
9.此时,bean已经准备就绪,可以被应用程序使用了,它们将一直驻留在应用上下文中,直到该应用上下文被销毁;
10.如果bean实现了DisposableBean接口,Spring将调用它的 destroy()接口方法。同样,如果bean使用destroy-method声明 了销毁方法,该方法也会被调用。