0
点赞
收藏
分享

微信扫一扫

[notes]Spring 3.x应用开发实战——陈雄华 林开雄


6、AOP基础


OOP是竖切, AOP是横切


连接点:joinpoint, 程序执行的某个特定位置


切点:pointcut, 通过切点定位具体的连接点


增强:advice, 织入到目标类连接点上的一段程序代码


目标对象:target


引介:introduction


织入:weaving, 增加添加到连接点上的过程


Spring AOP使用两种代理机制 :基于JDK的动态代理;基于CGLIB的动态代理。之所以需要两种,是因为JDK本身只提供接口的代理,不支持类的代理。


JDK动态代理 :java.lang.reflect包下的Proxy, InvocationHandler


1.编写一个handler类实现InvocationHandler接口,invoke方法:


public Object invoke(Object target, Method method, Object[] args) throws Throwable {


//代理前逻辑
 
Object obj = methos.invoke(target, args);
 
//代理后逻辑
 
return obj;
 
}


2.调用Proxy,


Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);//三个参数classLoader, interfaces, 实现invocationHandler的类


GCLib动态代理: JDK的限制:只能为接口创建代理实例.


CGLib采用非常底层的字节码技术,可以为一个类创建子类,并在子类中采用方法拦截技术拦截所有父类方法的调用,并顺势织入横切逻辑。


1、创建一个CGLibProxy实现MethodInterceptor


package com.billkang.springstudy;
import java.lang.reflect.Method;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

public class CGLibProxy implements MethodInterceptor {

	private Enhancer enhancer = new Enhancer();
	
	@SuppressWarnings("rawtypes")
	public Object getProxy(Class clazz) {
		enhancer.setSuperclass(clazz); //设置需要创建子类的类
		enhancer.setCallback(this);
		return enhancer.create(); //通过字节码技术动态创建子类实例
	}
	
	public Object intercept(Object obj, Method method, Object[] args,
			MethodProxy proxy) throws Throwable {
		System.out.println("代理前逻辑");
		Object result = proxy.invokeSuper(obj, args);
		System.out.println("代理后逻辑");
		return result;
	}
}


2、应用的时候 ForumServiceImpl service = ( ForumServiceImpl ) cgLibProxy.getProxy( ForumServcieImpl.class);


由于CGlib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final、private方法进行代理。


对于singleton的代理,推荐使用CGlib,对于其他作用域的代理,最好使用JDK,因为CGlib创建代理的时候慢,而创建出的代理对象运动效率极高,而使用JDK代理的表现刚好相反。


Spring切点检查 :在创建代理时对目标类的每个连接点使用静态切点检查,如果仅通过静态切点检查就可以知道连接点是不匹配的,则不再进行动态切点检查;如果静态切点检查是匹配的,在运行时才进行动态切点检查。


静态切点检查只执行一次,动态切点检查每次运行都会执行。


Spring只能在方法级别上织入增强,Spring提供了4种类型的方法增强,分别是前置增强、后置增强、环绕增强和异常抛出增强,此外还有一种特殊的引介增强,引介增强是类级别的,它为目标类织入新的接口实现。从广义上说,增强其实就是一种最简单的切面,它既包括横切代码也包括切点信息,只不过它的切点只是简单的方法相对位置的信息,所以增强一般需要和切点联合才可以表示一个更具实用性的切面。


7、基于@AspectJ和Schema的AOP


package com.billkang.springstudy;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * @author binkang
 * @date May 1, 2017
 */
@Retention(RetentionPolicy.RUNTIME) //声明注解的保留期限
@Target(ElementType.METHOD) //声明可以使用该注解的目标类型
public @interface AnnotationTest { //定义注解@interface
	boolean value() default true; //声明注解成员
}


注解成员的声明限制:


1)成员以无入参无抛出异常的方式声明,boolean value(String str),boolean value() throws Exception等都是非法的。


2)可以通过default为成员指定一个默认值,也可以不指定


3)成员类型是受限的,合法的类型包括原始类型及其封装类、String,Class,enums,注解类型,以及上述类型的数组类型。 ForumService value(),List foo()是非法的。


如果注解只有一个成员,则成员名必须是value(),在使用时可以忽略成员名和赋值号=,如@AnnotationTest(true). 注解可以没有成员,没有成员的注解称为标识注解,解释程序以标识注解存在与否进行相应的处理;此外,所有的注解类都隐式继承于java.lang.annotation.Annotation,但注解 不允许 显式继承于其他的接口。


@AspectJ采用注解来描述切点、增强,


使用哪种切面的选择:如果项目采用JDK5.0,可以优先考虑使用@AspectJ,如果项目只能使用低版本的JDK,则可以考虑使用<aop:aspect>;如果正在升级一个基于低版本Spring AOP开发的项目,则可以考虑使用<aop:advisor>复用已经存在的advisor类;如果项目只能使用低版本的Spring,那么就只能使用Advisor了。此外,值得注意的是一些切面只能使用基于API的Advisor方式进行构建,如基于ControlFlowPointcut的流程切面。


除了运行期织入切面的方式外,还可以在类加载期通过字节码编辑的技术,将切面织入到目标类中,这种织入方式称为LTW(Load Time Weaving).


8、Srping对DAO的支持


Spring 将数据访问流程划分为固定和变化两部分,并以模板的方式定义好流程,用回调接口将变化的部分开放出来,留给开发者自行定义。Spring为了进一步简化模板类的使用,为各种持久化技术提供了便捷的支持类,支持类不但包含数据访问模板,还包含数据源或会话等内容。通过扩展支持类定义自己的数据访问类是最简单的数据访问方式。


9、Spring事务管理


编程式事务需要你在代码中直接加入处理事务的逻辑,可能需要在代码中显式调用beginTransaction()、commit()、rollback()等事务管理相关的方法,如在执行a方法时候需要事务处理,你需要在a方法开始时候开启事务,处理完后。在方法结束时候,关闭事务.


声明式的事务的做法是在a方法外围添加注解或者直接在配置文件中定义,a方法需要事务处理,在spring中会通过配置文件在a方法前后拦截,并添加事务


事务4个特性:ACID Atomic原子性,Consistency一致性、Isolation隔离性、Durability持久性。


事务并发的问题:脏读、不可重复读、幻象读、每一类丢失更新、第二类丢失更新。


数据库锁机制:


行共享锁定


行独占锁定


表共享锁定


表共享行独占


表独占


4类隔离级别:


读不可提交、读可提交、可重复读、序列化


事务7类传播行为:


required: 使用当前事务,如果没有就新建


requres_new:新建一个事务,如果当前有事务就将当前事务挂起;


support: 支持当前事务,如果当前没有事务就以非事务方式执行;


mandatory: 使用当前事务,如果当前没有事务就抛异常


not support: 以非事务方式执行,如果当前有事务就挂起


never: 以非事务方式执行,如果当前有事务就抛异常


nested:如果当前存在事务就嵌套在事务内,如果当前没事务就执行required类似的操作


事务的传播行为。


14、使用OXM进行xml映射


Object XML Mapping


XStream别名:


类别名


类成员别名


类成员作为属性别名


XStream转换器:


implements Converter#
 
canConver(),//判断要转换的类型
 
marshal()//XML-->java
 
unmarshal()//java-->XML
 
XStream注解:
 
@XStreamAlias("user")
 
@XStreamAsAtribute
 
@XStreamConverter(DateConverter.class)
 
@XStreamImplict //隐式集合
 
@XStreamOmiField //忽略字段


应用的时候:


static {
 
xstream.processAnnotations(User.class);//
 
xstream.autodetectAnnotations(true);
 
}


流化对象:


xsteam.createObjectOutputStream(prettyPrintWriter);//objectToXML
 
xstream.creatObjectInputStream(bufferedReader);//XMLToObject


15、Spring MVC


initStrategies();
 
protected void initStrategies(ApplicationContext context) {
 
    
 initMultipartResolver();
 
    
 initLocaleResolver();
 
    
 initThemeResolver();
 
    
 initHandlerMappings();
 
    
 initHandlerAdapters();
 
    
 initHandlerExceptionResolvers();
 
    
 initRequestToViewNameTranslator();
 
    
 initViewResolvers();
 
}


initStratigies()方法在WebApplicationContext初始化后自动执行。


DispatcherServlet初始化后,会自动扫描上下文的Bean,根据名称或类型匹配的机制查找自定义的组件,找不到时则使用DispatcherServlet.properties定义的默认组件。



<context:component-scan base-package="com.baobaotao.web"/>
 
@Controller
 
@RequestMapping("/uer")  value,metod,params,headers



方法返回的字符串代表逻辑视图名。


返回ModelAndView


@RequestParam
 
@CookieValue
 
@RequestHeeader
 

 
 
HttpMessageConverter<T>
 
    
 AnnotationMetodHandlerAdapter默认已经封装了以下的HttpMessageConverter:
 
    
 StringHttpMessageConverter
 
    
 ByteArrayHttpMessageConverter
 
    
 SourceHttpMessageConverter
 
    
 XmlAwareFormHttpMessageConverter
 
    
 
<bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter" 
 p:messageConverters-ref=“messageConverters"
 />

自定义的messageConverters-ref将覆盖默认的



响应消息的格式,通过请求消息头“Content-Type”及“Accept”属性确定。


HttpHeaders entityHeaders = new HttpHeaders();
 
    
 entityHeaders.setContentType(MediaType.valueOf("application/json;UTF-8"));
 
    
 entityHeaders.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON));
 
    
 HttpEntity<User> requestEntity = new HttpEntity<User>(user, entityHeaders);


    


处理方法入参最多只能使用一个Spring MVC的注解,如使用了@ModelAttribute,就不能再使用@RequestParamore或@CookieValue。如果使用了两个注解,Spring MVC将抛出异常



Spring MVC一旦发现处理方法有Map或Model类型的入参,就会将请求内的隐含模型对象传递给这些参数。



@SessionAttributes



数据绑定:DataBinder


     数据转换:


         ConversionService,参考宿主类的上下文,并利用这些信息进行类型转换。


         @InitBinder,自定义编辑器


         WebBindingInitializer,装配在全局范围内使用的编辑器。


     数据格式化:


         Formatter<T>接口扩展于Printer<T> Parser<T>


        


视图解析器:


ViewResolver
 
    
 View resolveViewName(String viewName, Locale locale);
 

 
 
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver" p:prefix="/WEB-INF/views/" p:suffix=".jsp" />


InternalResourceIvewResolver默认使用InternalResourceView作为视图实现类。


模板视图:


FreeMarker



本地化解析:


报文头的Accept-language


Srping 提供了四种本地化解析(local resolver):


     AcceptHeaderLocaleResolver:(Spring默认采用)


     CookieLocaleResolver


     SessionLocaleResolver


     LocaleChangeInteceptor



文件上传:


MultipartResolver
 
    
 CommonsMultipartResolver
 
    
 <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver" 
 
    
 p:defaultEncoding="UTF-8"
 
    
 p:maxUplodaSize="5242800"
 
    
 p:uplodaTempDir="uploda/temp" />
 
    
 defaultEncoding必须和JSP的pageEncoding一致,uplodaTempDir 文件上传完成后,临时目录里的文件会被自动清除。


     有上传文件操作,表单的编码类型必须是:"multipart/form-data",即 <form enctype="multipart/form-data" />


    


静态资源处理:


<mvc:default-servlet-handler/> 将静态资源的处理经由Spring MVC框架交回Web应用服务器处理


<mvc;resources/> Spring MVC自己处理静态资源,并添加一些有用的附加功能。


16、单元测试


单元测试


集成测试


功能测试


系统测试


@Before


@After


分别可以有多个方法添加这两个注解


都使用public void 修饰,不能带参数




未完待续。。。

举报

相关推荐

0 条评论