AnnotationConfigApplicationContext:从一个或多个基于java配置类中加载Spring应用上下文
AnnotationConfigWebAppApplicationContext:从一个或多个基于java配置类中加载Spring Web应用上下文
ClassPathXmlApplicationContext:从类路径下的一个或多个XML文件中加载上下文定义,把上下文定义文件作为类资源
FileSystemXmlApplicationContext:从文件系统下的一个或多个XML文件中加载上下文定义
XmlWebApplicationContext:从WEB应用下的一个或多个XML文件中加载上下文定义
ApplicationContext context= new FileSystemXmlApplicationContext("c:/knight.xml");
ApplicationContext context= new ClassPathXmlApplicationContext("knight.xml");
ApplicationContext context= new
AnnotationConfigApplicationContext("com.springinaction.knight.config.Knight.class");
getBean(); 返回一个实例
//通过DI AOP和消除样板式代码来简化开发
Spring核心容器
Component named
Autowired Inject
javaConfig
@Configuration
@ComponentScan
public class CDPlayerConfig{
@Bean
public CDPlayer cdPlayer(){
return new CDPlayer(sgtPeppers()); //cdPlayer //sgtPeppers implements compactDisc
}
@Bean
public CDPlayer anthorCdPlayer(){
return new CDPlayer(sgtPeppers()); //cdPlayer
}
}
//这里调用了两次sgtPeppers,spring默认是单例模式,因此第二次调用的时候会拦截,并返回已经创建的bean,
//即同一个sgtPeppers
xml配置
方法一:
<bean id="cdPlayer" class="com.qmylzx.view.CDPlayer">
<constructor-arg ref="compactDisc"/>
<property name="compactDisc" ref="compactDisc"></property>
</bean>
方法二: c命名空间和模式声明 spring 3.0版本支持
<bean id="cdPlayer" class="com.qmylzx.view.CDPlayer" c:cd-ref="compactDisc"></bean>
c:cd-ref="compactDisc" 若参数为字符串 c:cd="hello world"
c: c命名空间
cd 构造器参数名
-ref 注入bean引用
compactDisc bean的名字
或者 c:_0-ref c:_1-ref 或者 c:_cd-ref 当只有一个构造器参数的时候可以 c:_-ref
当参数为list时 c命名空间不支持list
<bean id="cdPlayer" class="com.qmylzx.view.CDPlayer">
<constructor-arg>
<list> //<set></set>
<value></value> //<ref bean="beanName"/>
<value></value> //<ref bean="beanName"/>
<value></value> //<ref bean="beanName"/>
</list>
</constructor-arg>
</bean>
p命名空间 <bean id="cdPlayer" class="com.qmylzx.view.CDPlayer" p:compactDisc-ref="compactDisc"/>
p:compactDisc-ref="compactDisc" 若参数为字符串 p:compactDisc="hello world"
p: p命名空间
compactDisc 属性名
-ref 注入bean引用
compactDisc bean的名字
util-命名空间
<util:list id="trackList"> //给 List trackList; 赋值
<value></value>
<value></value>
<value></value>
</util:list>
<bean id="compactDisc" class="com.qmylzx.view.BlankDisc"
p:title="hello world" p:artist="hello world" p:tracks-ref="trackList" />
Class BlankDisc{
String title; String artist; List tracks;
}
util:
constant 引用某个类型的public static域,并将其暴露为bean
list 创建List类型的bean 其中包含值或引用
map 创建Map类型的bean 其中包含值或引用
properties 创建Properties类型的bean
property-path 引用一个bean 的属性 并暴露为bean
set 创建Set类型的bean 其中包含值或引用
@Configuration //引入CompactDisc 或者
@Import(CDConfig.class) //用第三个类@Import({CDConfig.class,CDPlayerConfig.class})
public class CDPlayerConfig{
@Bean
public CDPlayer cdPlayer(CompactDisc compactDisc){ return new CDPlayer(compactDisc)}
}
//@Import 引入java配置文件 引入xml用@ImportResource("classpath:config.xml")
<bean class="com.qmylzx.config.CDConfig"></bean> //xml中引入javaconfig配置
//<import resource="config.xml"/> 引入另外的xml配置
<!-- 开始组件扫描 -->
<context:component-scan base-package="com.qmylzx.ssm"></context:component-scan>
@Profile("dev") //多个类似的Bean,当激活名字为dev的Profile时Bean才会起作用
<bean profile="dev"></bean> // xml配置
@ActiveProfiles("dev") //在使用类下标记
在web.xml中 servlet下的
<init-param>
<param-name>spring.profiles.default</param-name>
<param-value>dev,dev2</param-value> //可以激活多个,激活彼此不相关的
//dev2<param-value>dev</param-value>
</init-param>
//首先看spring.profiles.active 再看spring.profiles.default 都没有则找没有profile标记的bean初始化
@Conditional(MyCondition.class) //spring4.0 给定的条件判定为真就激活这个bean
public interface Condition{boolean matches(ConditionContext c,AnnotatedTypeMetadata a);}
public MyCondition implements Condition{
boolean matches(ConditionContext c,AnnotatedTypeMetadata a){
Environment e = c.getEnvironment(); return e.containsProperty("dev");
}
}
//主要根据ConditionContext的条件进行判定 AnnotatedTypeMetadata可得到@Bean的还使用了什么注解
@Primary //一个接口存在多个实例化类bean的时候Spring无法判定使用哪一个
//使用这个标记,可以设置首选bean
<bean primary="true"></bean>
//若Primary后还存在歧义 则可以用qulifier 需要配合autowired inject一起使用
@Autowired
@Qulifier("指定类名")
@Component
@Qulifier("cold") //这里可以 指定类的 限定名 为cold 其他位置使用cold即可,不用担心该bean被重构
class{
}
@bean
@Qulifier("cold") //产生歧义的时候,可以自定义注解标签来代替Qulifier
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) //标记bean创建多少个
//Singleton 默认 @Scope("prototype")也可以
//Prototype 每次注入或Spring上下文获取创建一个新的
//Session WEB应用中每个会话创建一个
//Rquest WEB应用中每个req创建一个
<bean scope=""></bean>
@Scope(WebApplicationContext.SCOPE_SESSION,
proxyMode=ScopedProxyMode.INTERFACES) //基于接口
//proxyMode=ScopedProxyMode.INTERFACES标记只有当客户端使用时才被注入
//ScopedProxyMode.TARGET_CLASS 基于类
// //== proxyMode=ScopedProxyMode.INTERFACES
<bean scope=""><aop:scoped-proxy proxy-target-class="true"/></bean>
注入外部的值
@Configuration
@PropertySource("classpath:/com/qmylzx/app.properties")
public class ExpressConfig{
@Autowired
Environment env;
@Bean
public BlankDisc disc(){
return new BlankDisc(env.getProperty("disc.title"),env.getProperty("disc.artist"));
}//这里getProperty配置文件为空获取null
} //getRequiredProperty("disc.title") 配置文件为空则抛出异常
app.properties
disc.title=hello world
disc.artist=xx
SpringEL
#{语句}
#{实例类名} //获取类
#{double.属性名} //获取类属性
#{double.getInt()?.toString()} //这里? 表示会检测getInt()方法返回值是否为null,
//null的话不会调用toString()方法
@Value("#{systemProperties=['disc.title']}") //获取配置文件属性
#{2*T(java.lang.Math).PI*R^2} //T()返回一个Class对象 算术运算
#{disc.title+'by'+disc.artist} //连接字符串 比较 == eq
#{disc.email matches '[a-zA-z0-9]'} // matches '[a-zA-z0-9]'正则表达式
#{muisicbox.songs[T(java.java.lang.Math).random()*10]} // []取值
#{muisicbox.songs.?[artist eq 'Alan worker']} // .?[] 对集合进行过滤
//.^[] .$[] .![]
面向切面的Spring
即:贯穿多个Service的某些方法的横切关注点 如:日志、事务、安全等
横切关注点可以模块化为特殊的类,这些类被称为切面;
通知advice
切面的工作
1.Before
2.After
3.After-returning
4.After-throwing
5.Around 通知包裹了被通知的方法,在被通知方法调用之前和之后执行自定义的行为
连接点joinpoint
在应用程序执行过程中能插入切面的一个点,这个点可以是 调用方法、抛出异常、修改字段
切面代码可以利用这些点插入到应用到正常流程中并 添加新的行为
切点pointcut
切点有助于缩小 切面所通知的 连接点 的范围
通知定义切面的“什么”和“何时” 切点 定义“何处”
切面
通知与切点的结合
引入(Introduction)
允许我们向现有的类添加新的属性和方法。例如:创建Auditable类,记录对象最后一次修改时的状态
只需要一个setLastModified(Date);方法和实例变量保存该状态就可以了,从而可以在不修改原有类的
基础上使其有新的行为和状态。
织入(Weaving)
把切面应用到目标对象并创建新的代理对象的过程。切面在指定的连接点织入到目标对象中,有多个点可以织入
1.编译期:需要特殊的编译器 AspectJ织入编译器
2.类加载期:加载到jvm时被织入 需要特殊的类加载器 AspectJ 5支持load-time waving LTW
3.运行期:应用在运行的某个时刻被织入。 Spring AOP
Spring AOP 因为 Spring 基于 动态代理 只支持 方法级别 的AOP,需要其他级别可用 Aspect 补充
1.基于代理的经典Spring AOP
2.纯POJO切面
3.@AspectJ注解驱动的切面 //前三种是Spring AOP的变体
4.注入式AspectJ切面(适用于Spring各版本)
package com.qmylzx.concert;
public interface Performence {
void perfrom();
}
//springxml下可用//and or not
execution(* concert.Performence.perfrom(..) && within(concert.*)) // && || !
execution 在方法执行时触发
* 返回任意类型
concert.Performence 方法所属的类型
perfrom 方法
(..) 使用任意参数
within(concert.*) 在concert包下任意类的方法被调用时 执行
bean('beanName') 在指定beanName的方法被调用时 执行
package com.qmylzx.concert;
import org.aspectj.lang.annotation.*;
@Aspect
public class Audience {
@Pointcut("execution(** com.qmylzx.concert.Performence.perform(..))")
public void performence(){}
@Before("performence()")// @Before("execution(** com.qmylzx.concert.Performence.perform(..))")
public void slienceCellPhone() {//ready
System.out.println("slienceCellPhone");
}
@AfterReturning("performence()")
public void appluse(){//success
System.out.println("appluse appluse appluse!");
}
@AfterThrowing("performence()")
public void fail(){
System.out.println("fail!!!");
}
@Around("performence()")
public void safe(ProceedingJoinPoint proceedingJoinPoint){
System.out.println("注意安全");
proceedingJoinPoint.proceed();//调用Perform的方法
System.out.println("注意安全");
}
}
package com.qmylzx.concert;
@Configuration
@EnableAspectJAutoProxy //启用AspectJ注解的自动代理
@ComponentScan
public class ConcertConfig {
@Bean
public Audience audience(){
return new Audience();
}
}
<aop:aspectj-autoproxy/> //springxml启用AspectJ注解的自动代理
//记录磁道被使用的次数
@Pointcut("execution(* sound.cd.playTrack(int))"+"args(trackNumber)");
public void trackPlayed(int trackNumber){}
args(trackNumber) 指定参数 表明传到playTrack()的int参数也会传到通知中去
trackNumber与方法前面匹配
Before("trackPlayed(trackNumber)")
------------------------------------------------------------------------------
@Aspect
class EncoreableIntroducer{
@DeclareParents(value="com.qmylzx.concert.Performence+",
defaultImpl=DefaultEncoreable.class)
public static Encoreable en;
}
//没有使用通知,而是使用DeclareParents将Encoreable 接口引入Performence bean中
//value指定哪种类型的bean要引入该接口 Performence+ 表示 Performence 的子类型
//defaultImpl指定为了引入功能提供实现的类
//静态属性 指定了要引入的接口
同时需要 <bean class="com.qmylzx.concert.EncoreableIntroducer">
<aop:aspect>
<aop:declare-parents types-matching="concert.Performance+"
implements-interface="concert.Encoreable"
default-impl="concert.DefaultEncoreable">
</aop:declare-parents> // default-impl可替换为delegate-ref="beanname"
</aop:aspect> //其中<bean id="beanname" class="concert.DefaultEncoreable" />
------------------------------------------------------------------------------------
<aop:config>
<aop:aspect ref="Audience">
<aop:pointcut id="per" expression="* concert.Performence.perfrom(..)"/>
<aop:before method="slienceCellPhone" pointcut="execution(**
com.qmylzx.concert.Performence.perform(..))"></aop:before>
// pointcut-ref = "per"
</aop:aspect>
</aop:config>
<aop:config>
<aop:aspect ref="trackCounter">
<aop:pointcut id="trackPlayed"
expression="execution(* com.qmylzx.concert.TrackCounter.playTrack(int)) and args(trackNumber)"/>
<aop:before method="countTrack" pointcut-ref="trackPlayed"></aop:before>
</aop:aspect>
</aop:config>
//注入AspectJ切面
<bean class="com.qmylzx.CriticAspect" factory-method="aspectof" >
<property name="criticEngine" ref="criticEngine"></property>
</bean>
//这个切面是在方法执行完成以后才注入的criticEngine 而CriticAspect在开始阶段就已经创建
//现在要注入只能使用AspectJ自带的静态aspectof方法 需要指定factory-method="aspectof"
标注以后方法直接获取而不用requestget
@RequertParam("") @RequertParam(value="",defaultValue="")
//也可以 /ssm/admin?spittleId=123456
@RequestMapping(/{spittleId}) //解析123456为参数 /ssm/admin/123456
public String spittr(@PathVariable("spittleId") long spittleId){
}
视图解析器
InteranlResourceViewResolver --JSP
VelocityViewResolver --Velocity
FreeMarkerViewResolver -- FreeMarker
ThymeleafViewResolver --Thymeleaf
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/view/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
配置 支持Thymeleaf
<bean id="viewResolver" class="org.thymeleaf.spring3.view.ThymeleafViewResolver"
p:templateEngine-ref="templateEngine"/>
<bean id="templateEngine" class="org.thymeleaf.spring3.SpringTemplateEngine"
p:templateResolver-ref="templateResolver"/>
<bean id="templateResolver" class="org.thymeleaf.templatesesolver.ServletContextTemplateResolver"
P:prefix="/WEB-INF/view/" p:suffix=".html" p:templateMode="HTML5"/>
<a th:href="@{/spittles}">Spittles</a>
//抛出异常的时候会返回相应的HTTP状态码
@ResponseStatus(value=HttpStatus.NOT_FOUND,reason="not found")//404
public class MyException extends Exception{
}
@ExceptionHandler(MyException.class) //标记方法,抛出MyException异常会调用被标记的方法
@ControllerAdvice 标记的类为所有Controller处理异常
return "redirect:/admin/test"; //重定向到test页面,当前req的数据会丢失
参数列表中RedirectAttributes model
model.addAttribute(key,obj);
model.addFlashAttribute(key,obj); //会存数据到重定向的请求中
Spring Web Flow //流程化应用程序,例如购买商品一步接一步
<flow:flow-executor id="flowExecutor"/> //1..装配流程执行器
<flow:flow-registry id="flowregistry" base-path="/WEB-INF/flows"> //2..配置流程注册表
<flow:flow-location-pattern value="*-flow.xml"/>
</flow:flow-registry> //以-flow.xml结尾的XML视为流程定义
流程注册表基本路径 流程定义
flow-location-pattern == /WEB-INF/flows + order + order-flow.xml
流程ID
//或者
<flow:flow-location path="/WEB-INF/flows/order.xml"/> //流程ID order
//3..处理流程请求
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerMapping">
<property name="flowregistry" ref="flowregistry"
</bean>
//FlowHandlerMapping定义了一个id为order的流程,若请求的URL模式是(相对应用上下文路径)'/order'
//就会匹配到这个流程上
//4..响应请求
<bean class="org.springframework.webflow.mvc.servlet.FlowHandlerAdapter">
<property name="flowExecutor" ref="flowExecutor"></property>
</bean>
Spring Web Flow可选状态
行为(Action) 流程逻辑发生的地方
决策(Decision) 将流程分为两个方向,基于数据的评估结果确定流程方向
End 流程终止
Subflow 子流程
View 暂停流程并邀请用户参与流程
<view-state id="welcome"/> //在流程内标识这个状态,没指定其它视图,则默认welcome视图
<view-state id="welcome" view="greeting"/> //自定义视图
<view-state id="takePayment" model="flowScope.paymentDetails"/> //指明表单捆绑的对象
行为状态触发bean的方法并且根据方法执行结果转移到另外的状态
<action-state>
<evaluate expression="pizzaFlowActions.saveOrder(order)"/> //行为状态要做的事情
<transition to="thankYou"/>
</action-state>
<dicision-state id="checkDeliveryArea">
<if test="pizzaFlowActions.checkDeliveryArea(customer.zipCode)"
then="addCustomer" else="deliveryWarning"/>
</dicision-state>
<subflow-state id="order" subflow="pizza/order">
<input name="order" value="order"/>
<transition on="orderCreated" to="payment"/> //子流程end状态为orderCreated则进入payment
</subflow-state>
<end-state id="orderCreated" /> //view="se" flowRedirect:
转移transition
on 触发转移事件 to转移
on-exception="com.MyException"
<global-transitions> //全局状态转移,所有状态都会拥有这个属性
<transition></transition>
</global-transitions>
<var name="customer" class="com.customer">
<evaluate result="viewScope.toppingsList" //计算结果放到toppingsList中
expression="T(com.Topping).asList()"/>
<set name="flowScope.pizza" value="new com.domain.Pizza()">
Spring Web Flow作用域
Conversation 最高层的流程开始创建,结束时销毁,被所有流程共享
Flow 流程开始创建,结束销毁 ,只有创建它的流程可以看到它
Request 请求进入流程时创建,流程返回时销毁
Flash 流程开始创建,结束销毁
View 进入视图创建 ,结束销毁 ,只在视图内可见
start--> identify Customter -(customterReady)->builderOrder-(orderCreated)->takePayment
-(paymentTaken)->saveOrder-->thankCustomter
RPC
RMI、Hessian和Burlap、HTTP invoker、JAX-RPC和JAX-WS
2进制消息 xml消息
RMI配置
RmiServiceExporter 来配置注册rpc服务
//服务端
@Bean
public RmiServiceExporter rmiServiceExporter(){
RmiServiceExporter r = new RmiServiceExporter();
r.setService(SpitterService);
r.setServiceName("SpitterService");
r.setServiceInterface(SpitterService.class);
r.setRegistryHost("rmi.spitter.com");//绑定服务到rmi.xx.com主机的1199端口
r.setRegistryPort(1199);
return r;
}
//客户端
@Bean
public RmiProxyFactoryBean spitterService(){
RmiProxyFactoryBean rmiProxy= new RmiProxyFactoryBean();
rmiProxy.setServiceUrl("rmi://localhost/SpitterService");
rmiProxy.setServiceInterface(SpitterService.class);
return rmiProxy;
}
//客户端使用
@Autowired
SpitterService spitterService; //调用方法即可
------------------------------------------------------------
使用Hessian和Burlap 具有移植性
service extends HessianServlet 且方法为public
////服务端
@Bean
public HessianServiceExporter hessianServiceExporter(){
HessianServiceExporter h = new HessianServiceExporter();
h.setService(SpitterService);
h.setServiceInterface(SpitterService.class);
return h;
}
配置控制器
<servlet-mapping>
<servlet-name>spitter</servlet-name>
<servlet-pattern>*.service</servlet-pattern>
</servlet-mapping>
@Bean
public HandlerMapping hessianMapping(){
SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
Properties mappings = new Properties();
mappings.setProperty("/spitter","hessianExportedSpitterService");
mapping.setMappings(mappings);
return mapping;
}
//客户端
@Bean
public HessianProxyFactoryBean spitterService(){
HessianProxyFactoryBean hessianProxy= new HessianProxyFactoryBean();
hessianProxy.setServiceUrl("http://localhost:8080/Spitter/spitter.service");
hessianProxy.setServiceInterface(SpitterService.class);
return hessianProxy;
}
Restful URL
Create Post
Read Get
Update PUt\Patch
Delete Delete