spring实战笔记

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

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章