Spring的Bean,AOP以及工具类初探

1.Bean(Ioc)

BeanWrapper

根据JavaDoc中的说明,BeanWrapper提供了设置和获取属性值(单个的或者是批量的),获取属性描述信息、查询只读或者可写属性等功能。不仅如此,BeanWrapper还支持嵌套属性,你可以不受嵌套深度限制对子属性的值进行设置。Spring 从核心而言,是一个DI 容器,其设计哲学是提供一种无侵入式的高扩展性框架。即无需代 码中涉及Spring专有类,即可将其纳入Spring容器进行管理。 作为对比,EJB则是一种高度侵入性的框架规范,它制定了众多的接口和编码规范,要求实现者必须 遵从。侵入性的后果就是,一旦系统基于侵入性框架设计开发,那么之后任何脱离这个框架的企图都将付 出极大的代价。 为了避免这种情况,实现无侵入性的目标。Spring 大量引入了Java 的Reflection机制,通过动态 调用的方式避免硬编码方式的约束,并在此基础上建立了其核心组件BeanFactory,以此作为其依赖注入 机制的实现基础。 org.springframework.beans包中包括了这些核心组件的实现类,核心中的核心为BeanWrapper 和BeanFactory类。

BeanWrapper示例

public class Company {
    @Setter @Getter
    private String name;

    @Setter @Getter
    private Employee manager;

}
public class Employee {
    @Setter @Getter
    private String name;

    @Setter @Getter
    private float salary;
}

BeanWrapper companyWrapper = new BeanWrapperImpl(new Company());
companyWrapper.setPropertyValue("name","alibaba-inc...");
PropertyValue cname = new PropertyValue("name","taobao....");
companyWrapper.setPropertyValue(cname);

BeanWrapper employWrapper = new BeanWrapperImpl(new Employee());
employWrapper.setPropertyValue("name","chuanqing");
companyWrapper.setPropertyValue("manager",employWrapper.getWrappedInstance());

Float salary = (Float) companyWrapper.getPropertyValue("manager.salary");

String name = (String)companyWrapper.getPropertyValue("manager.name");
System.out.println(name);

BeanFactory

类图结构

  • BeanFactory作为一个主接口不继承任何接口,暂且称为一级接口。
  • 有3个子接口继承了它,进行功能上的增强。这3个子接口称为二级接口。
  • ConfigurableBeanFactory可以被称为三级接口,对二级接口HierarchicalBeanFactory进行了再次增强,它还继承了另一个外来的接口SingletonBeanRegistry
  • ConfigurableListableBeanFactory是一个更强大的接口,继承了上述的所有接口,无所不包,称为四级接口。(这4级接口是BeanFactory的基本接口体系。继续,下面是继承关系的2个抽象类和2个实现类:)
  • AbstractBeanFactory作为一个抽象类,实现了三级接口ConfigurableBeanFactory大部分功能。
  • AbstractAutowireCapableBeanFactory同样是抽象类,继承自AbstractBeanFactory,并额外实现了二级接口AutowireCapableBeanFactory
  • DefaultListableBeanFactory继承自AbstractAutowireCapableBeanFactory,实现了最强大的四级接口ConfigurableListableBeanFactory,并实现了一个外来接口BeanDefinitionRegistry,它并非抽象类。
  • 最后是最强大的XmlBeanFactory,继承自DefaultListableBeanFactory,重写了一些功能,使自己更强大。

InitializingBean

  • spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中同过init-method指定,两种方式可以同时使用。
  • Spring的加载bean的源码类(AbstractAutowireCapableBeanFactory)。
  • spring为bean提供了两种初始化bean的方式,实现InitializingBean接口,实现afterPropertiesSet方法,或者在配置文件中同过init-method指定,两种方式可以同时使用
  • 实现InitializingBean接口是直接调用afterPropertiesSet方法,比通过反射调用init-method指定的方法效率相对来说要高点。但是init-method方式消除了对spring的依赖
  • 如果调用afterPropertiesSet方法时出错,则不调用init-method指定的方法。

CustomEditorConfigurer,PropertyEditorRegistrar,PropertyEditorSupport

特殊的bean factory后置处理器,通过CustomEditor绑定Registrar,为指定Bean 执行自定义的绑定(比如动态代理)。

PropertyEditorRegistrar示例
public class HSFSpringProviderBeanRegistrar implements
PropertyEditorRegistrar {

	@Override
	public void registerCustomEditors(PropertyEditorRegistry registry) {
		if(!(registry instanceof BeanWrapperImpl)) {
			return ;
		}
		
		BeanWrapperImpl beanWrapper = (BeanWrapperImpl) registry;
		
		Class<?> clazz = null;
		try {
			clazz = Class.forName("com.taobao.hsf.app.spring.util.HSFSpringProviderBean", true, registry.getClass().getClassLoader());
		} catch (Throwable e) {
			RecordLog.info("cannot find class for com.taobao.hsf.app.spring.util.HSFSpringProviderBean", e);
		}
		
		if(null == clazz 
				|| null == beanWrapper.getWrappedClass()
				|| !clazz.isAssignableFrom(beanWrapper.getWrappedClass())) {
			return ;
		}
		
		registry.registerCustomEditor(Object.class, "target", new HSFSpringProviderBeanTargetEditor());
	}

}

HSFSpringProviderBeanTargetEditor示例

public class HSFSpringProviderBeanTargetEditor extends PropertyEditorSupport {
	
	@Override
	public void setValue(Object value) {
		if(value != null && needProxy(value)) {
			try {
				Class<?>[] classes = MethodUtil.getAllInterfaces(value.getClass());
				InvocationHandler invocationHandler = new HsfProviderInvocationHandler(value);
				
				Object object = Proxy.newProxyInstance(value.getClass().getClassLoader(), classes, invocationHandler);
				super.setValue(object);
				RecordLog.info("success to proxy hsf provider bean typed: " + value.toString());
				return ;
			} catch (Exception e) {
				RecordLog.info(e.getClass().getName(), e);
			}
			super.setValue(value);
		}
		
		super.setValue(value);
	}
	
	/***
	 * 需要注意多次代理
	 * @param value
	 * @return
	 */
	private boolean needProxy(Object value) {
		if (Proxy.isProxyClass(value.getClass())) {
			InvocationHandler invocationHandler = Proxy.getInvocationHandler(value);
			if (!(invocationHandler instanceof HsfProviderInvocationHandler)) {
				return true;
			} else {
				return false;
			}
		} else {
			return true;
		}
	}
}

2.AOP

一、AOP 概念

  • Joinpoint:它定义在哪里加入你的逻辑功能,对于Spring AOP,Jointpoint指的就是Method。
  • Advice:特定的Jointpoint处运行的代码,对于Spring AOP 来讲,有Before advice、AfterreturningAdvice、ThrowAdvice、AroundAdvice(MethodInteceptor)等。
  • Pointcut:一组Joinpoint,就是说一个Advice可能在多个地方织入,
  • Aspect:这个我一直迷惑,它实际是Advice和Pointcut的组合,但是Spring AOP 中的Advisor也是这样一个东西,但是Spring中为什么叫Advisor而不叫做Aspect。
  • Weaving:将Aspect加入到程序代码的过程,对于Spring AOP,由ProxyFactory或者ProxyFactoryBean负责织入动作。
  • Target:这个很容易理解,就是需要Aspect功能的对象。
  • Introduction:引入,就是向对象中加入新的属性或方法,一般是一个实例一个引用对象。当然如果不引入属性或者引入的属性做了线程安全性处理或者只读属性,则一个Class一个引用也是可以的(自己理解)。Per-class lifecycle or per-instance life cycle

二、AOP 种类

  • 静态织入:指在编译时期就织入Aspect代码,AspectJ好像是这样做的。
  • 动态织入:在运行时期织入,Spring AOP属于动态织入,动态织入又分静动两种,静则指织入过程只在第一次调用时执行;动则指根据代码动态运行的中间状态来决定如何操作,每次调用Target的时候都执行(性能较差)。

三、Spring AOP 代理原理

Spring AOP 是使用代理来完成的,Spring 会使用下面两种方式的其中一种来创建代理

  • JDK动态代理,特点只能代理接口,性能相对较差,需要设定一组代理接口。
  • CGLIB 代理,可代理接口和类(final method除外),性能较高(生成字节码)。

四、Spring AOP 通知类型

  • BeforeAdvice:前置通知需实现MethodBeforeAdvice,但是该接口的Parent是BeforeAdvice,致于什么用处我想可能是扩展性需求的设计吧。或者Spring未来也并不局限于Method的JoinPoint(胡乱猜测)。BeforeAdvice可以修改目标的参数,也可以通过抛出异常来阻止目标运行。
  • AfterreturningAdvice:实现AfterreturningAdvice,我们无法修改方法的返回值,但是可以通过抛出异常阻止方法运行。
  • AroundAdvice:Spring 通过实现MethodInterceptor(aopalliance)来实现包围通知,最大特点是可以修改返回值,当然它在方法前后都加入了自己的逻辑代码,因此功能异常强大。通过MethodInvocation.proceed()来调用目标方法(甚至可以不调用)。
  • ThrowsAdvice:通过实现若干afterThrowing()来实现。
  • IntroductionInterceptor:Spring 的默认实现为DelegatingIntroductionInterceptor

五、Spring AOP Pointcut

以上只是Advice,如果不指定切入点,Spring 则使用所有可能的Jointpoint进行织入(当然如果你在Advice中进行方法检查除外)。因此切入点在AOP中扮演一个十分重要的角色。Spring 2.0 推荐使用AspectJ的Annocation的切入点表达式来定义切入点,或者使用aop:xxx/来定义AOP,这方面本篇不做考虑。

  • Pointcut:它是Spring AOP Pointcut的核心,定义了getClassFilter()和getMethodMatcher()两个方法。
  • ClassFilter:定义了matches(Class cls)一个方法。
  • MethodMatcher() 定义了matches(Method,Class),isRuntime(),matches(Mathod,Class,Object[])三个方法,如果isRuntime()返回true则表示为动态代理(实际是动态代理的动态代理),则调用第三个方法(每访问一次调用一次),否则调用第一个方法(并且只调用一次)

Spring AOP 静态切入点的几个实现。

  • ComposablePointcut 太复杂一个切入点无法表达就用这个,union MethodMatcher和ClassFilter或者intersection MethodMatcher、ClassFilter和Pointcut。为什么不实现union Pointcut? 而只能通过Pointcuts类对Pointcut进行union操作。
  • ControlFlowPointcut 想对程序的运行过程进行追踪就用这个
  • DynamicMatchMatcherPointcut 想用动态AOP 就用这个
  • JdkRegexpMethodPointcut 想使用正则表达式就用这个
  • Perl5RegexpMethodPointcut
  • NameMatchMethodPointcut 想用方法名字来匹配就用这个
  • StaticMethodMatcherPointcut 静态切入点就用这个
    没有人反对你直接实现Pointcut。

六、Spring AOP 中的Advisor其实就是Aspect

  • PointcutAdvisor:
    其实一般使用DefaultPointcutAdvisor就足够了,给它Advice和Pointcut。 当然如果想少写那么几行代码也可以使用NameMatchMethodPointcutAdvisor,RegexpMethodPointcutAdvisor等。 更多Advisor可以查看API文档。

  • IntroductionAdvisor:
    默认实现为DefaultIntroductionAdvisor。

七、AOP ProxyFactory

使用代码实现AOP 可使用ProxyFactory
声明式AOP 可使用ProxyFactoryBean
ProxyFactoryBean 需要设定 target,interceptorNames(可以是Advice或者Advisor,注意顺序)
对接口代理需设置proxyInterfaces

3.工具包

内置的resouce类型

  • UrlResource
  • ClassPathResource
  • FileSystemResource
  • ServletContextResource
  • InputStreamResource
  • ByteArrayResource
  • EncodedResource 也就是Resource加上encoding, 可以认为是有编码的资源
  • VfsResource(在jboss里经常用到, 相应还有 工具类 VfsUtils)
  • org.springframework.util.xml.ResourceUtils 用于处理表达资源字符串前缀描述资源的工具. 如: "classpath:".
  • 有 getURL, getFile, isFileURL, isJarURL, extractJarFileURL

工具类

  • org.springframework.core.annotation.AnnotationUtils 处理注解
  • org.springframework.core.io.support.PathMatchingResourcePatternResolver 用 于处理 ant 匹配风格(com/.jsp, com/**/.jsp),找出所有的资源, 结合上面的resource的概念一起使用,对于遍历文件很有用. 具体请详细查看javadoc
  • org.springframework.core.io.support.PropertiesLoaderUtils 加载Properties资源工具类,和Resource结合
  • org.springframework.core.BridgeMethodResolver 桥接方法分析器. 关于桥接方法请参考: http://java.sun.com/docs/books/jls/third_edition/html/expressions.html#15.12.4.5
  • org.springframework.core.GenericTypeResolver 范型分析器, 在用于对范型方法, 参数分析.
  • org.springframework.core.NestedExceptionUtils

xml工具

  • org.springframework.util.xml.AbstractStaxContentHandler
  • org.springframework.util.xml.AbstractStaxXMLReader
  • org.springframework.util.xml.AbstractXMLReader
  • org.springframework.util.xml.AbstractXMLStreamReader
  • org.springframework.util.xml.DomUtils
  • org.springframework.util.xml.SimpleNamespaceContext
  • org.springframework.util.xml.SimpleSaxErrorHandler
  • org.springframework.util.xml.SimpleTransformErrorListener
  • org.springframework.util.xml.StaxUtils
  • org.springframework.util.xml.TransformerUtils

其它工具集

  • org.springframework.util.xml.AntPathMatcherant风格的处理
  • org.springframework.util.xml.AntPathStringMatcher
  • org.springframework.util.xml.Assert断言,在我们的参数判断时应该经常用
  • org.springframework.util.xml.CachingMapDecorator
  • org.springframework.util.xml.ClassUtils用于Class的处理
  • org.springframework.util.xml.CollectionUtils用于处理集合的工具
  • org.springframework.util.xml.CommonsLogWriter
  • org.springframework.util.xml.CompositeIterator
  • org.springframework.util.xml.ConcurrencyThrottleSupport
  • org.springframework.util.xml.CustomizableThreadCreator
  • org.springframework.util.xml.DefaultPropertiesPersister
  • org.springframework.util.xml.DigestUtils摘要处理, 这里有用于md5处理信息的
  • org.springframework.util.xml.FileCopyUtils文件的拷贝处理, 结合Resource的概念一起来处理, 真的是很方便
  • org.springframework.util.xml.FileSystemUtils
  • org.springframework.util.xml.LinkedCaseInsensitiveMap
  • key值不区分大小写的LinkedMap
  • org.springframework.util.xml.LinkedMultiValueMap一个key可以存放多个值的LinkedMap
  • org.springframework.util.xml.Log4jConfigurer一个log4j的启动加载指定配制文件的工具类
  • org.springframework.util.xml.NumberUtils处理数字的工具类, 有parseNumber 可以把字符串处理成我们指定的数字格式, 还支持format格式, convertNumberToTargetClass 可以实现Number类型的转化.
  • org.springframework.util.xml.ObjectUtils有很多处理null object的方法. 如nullSafeHashCode, nullSafeEquals, isArray, containsElement, addObjectToArray, 等有用的方法
  • org.springframework.util.xml.PatternMatchUtilsspring里用于处理简单的匹配. 如 Spring's typical "xxx", "xxx" and "xxx" pattern styles
  • org.springframework.util.xml.PropertyPlaceholderHelper用于处理占位符的替换
  • org.springframework.util.xml.ReflectionUtils反映常用工具方法. 有 findField, setField, getField, findMethod, invokeMethod等有用的方法
  • org.springframework.util.xml.SerializationUtils用于java的序列化与反序列化. serialize与deserialize方法
  • org.springframework.util.xml.StopWatch一个很好的用于记录执行时间的工具类, 且可以用于任务分阶段的测试时间. 最后支持一个很好看的打印格式. 这个类应该经常用
  • org.springframework.util.xml.StringUtils
  • org.springframework.util.xml.SystemPropertyUtils
  • org.springframework.util.xml.TypeUtils用于类型相容的判断. isAssignable
  • org.springframework.util.xml.WeakReferenceMonitor弱引用的监控

和web相关的工具

  • org.springframework.web.util.CookieGenerator
  • org.springframework.web.util.HtmlCharacterEntityDecoder
  • org.springframework.web.util.HtmlCharacterEntityReferences
  • org.springframework.web.util.HtmlUtils
  • org.springframework.web.util.HttpUrlTemplate 这个类用于用字符串模板构建url, 它会自动处理url里的汉字及其它相关的编码. 在读取别人提供的url资源时, 应该经常用
  • String url = "http://localhost/myapp/{name}/{id}"
  • org.springframework.web.util.JavaScriptUtils
  • org.springframework.web.util.Log4jConfigListener 用listener的方式来配制log4j在web环境下的初始化
  • org.springframework.web.util.UriTemplate
  • org.springframework.web.util.UriUtils处理uri里特殊字符的编码
  • org.springframework.web.util.WebUtils
  • org.springframework.web.util.

为什么引入spring-beans.dtd相对路径文件

maybe 减少网络传输

原文地址:https://www.cnblogs.com/zhulongchao/p/5539782.html