spring源代码解析一

spring源代码解析一
spring源代码解析一

Spring源代码解析(一):Spring中的事务处理

2009-08-11 (周二) 10:50 Spring Spring ? 被围观一共有3,166 个打酱油的路过+ 在认真学习Rod.Johnson的三部曲之一:<>,顺便也看了看源代码想知道个究竟,抛砖引玉,有兴趣的同志一起讨论研究吧!

在Spring中,IOC容器的重要地位我们就不多说了,对于Spring的使用者而言,IOC容器实际上是什么呢?我们可以说BeanFactory就是我们看到的IoC容器,当然了Spring为我们准备了许多种IoC容器来使用,这样可以方便我们从不同的层面,不同的资源位置,不同的形式的定义信息来建立我们需要的IoC容器。

在Spring中,最基本的IOC容器接口是BeanFactory –这个接口为具体的IOC容器的实现作了最基本的功能规定–不管怎么着,作为IOC容器,这些接口你必须要满足应用程序的最基本要求:

如转载请注明,转载自:关注Java[https://www.360docs.net/doc/c6907222.html,]

本文链接: https://www.360docs.net/doc/c6907222.html,/2009/08/11/212.html

-

-

Java代码

public interface BeanFactory {

//这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,

//如果需要得到工厂本身,需要转义

String FACTORY_BEAN_PREFIX = "&";

//这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。

Object getBean(String name) throws BeansException;

//这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。

Object getBean(String name, Class requiredType) throws BeansException;

//这里提供对bean的检索,看看是否在IOC容器有这个名字的bean

boolean containsBean(String name);

//这里根据bean名字得到bean实例,并同时判断这个bean是不是单件

boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

//这里对得到bean实例的Class类型

Class getType(String name) throws NoSuchBeanDefinitionException;

//这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来

String[] getAliases(String name);

}

public interface BeanFactory {

//这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,

//如果需要得到工厂本身,需要转义

String FACTORY_BEAN_PREFIX = "&";

//这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。

Object getBean(String name) throws BeansException;

//这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。

Object getBean(String name, Class requiredType) throws BeansException;

//这里提供对bean的检索,看看是否在IOC容器有这个名字的bean

boolean containsBean(String name);

//这里根据bean名字得到bean实例,并同时判断这个bean是不是单件

boolean isSingleton(String name) throws NoSuchBeanDefinitionException;

//这里对得到bean实例的Class类型

Class getType(String name) throws NoSuchBeanDefinitionException;

//这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来

String[] getAliases(String name);

}

在BeanFactory里只对IOC容器的基本行为作了定义,根本不关心你的bean是怎样定义怎样加载的–就像我们只关心从这个工厂里我们得到到什么产品对象,至于工厂是怎么生产这些对象的,这个基本的接口不关心这些。如果要关心工厂是怎样产生对象的,应用程序需要使用具体的IOC容器实现- 当然你可以自己根据这个BeanFactory来实现自己的IOC容器,但这个没有必要,因为Spring已经为我们准备好了一系列工厂来让我们使用。比如XmlBeanFactory就是针对最基础的BeanFactory的IOC容器的实现–这个实现使用xml来定义IOC容器中的bean。

Spring提供了一个BeanFactory的基本实现,XmlBeanFactory同样的通过使用模板模式来得到对IOC容器的抽象- AbstractBeanFactory,DefaultListableBeanFactory这些抽象类为其提供模板服务。其中通过resource 接口来抽象bean定义数据,对Xml定义文件的解析通过委托给XmlBeanDefinitionReader来完成。下面我们根据书上的例子,简单的演示IOC容器的创建过

程:

Java代码

ClassPathResource res = new ClassPathResource("beans.xml"); DefaultListableBeanFactory factory = new DefaultListableBeanFactory(); XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(res);

ClassPathResource res = new ClassPathResource("beans.xml");

DefaultListableBeanFactory factory = new DefaultListableBeanFactory();

XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(res);

这些代码演示了以下几个步骤:

1. 创建IOC配置文件的抽象资源

2. 创建一个BeanFactory

3. 把读取配置信息的BeanDefinitionReader,这里是XmlBeanDefinitionReader配置给BeanFactory

4. 从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成,这样完成整个载入bean定义的过程。我们的IoC容器就建立起来了。在BeanFactory的源代码中我们可以看到:

Java代码

public class XmlBeanFactory extends DefaultListableBeanFactory {

//这里为容器定义了一个默认使用的bean定义读取器

private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

public XmlBeanFactory(Resource resource) throws BeansException {

this(resource, null);

}

//在初始化函数中使用读取器来对资源进行读取,得到bean定义信息。

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {

super(parentBeanFactory);

this.reader.loadBeanDefinitions(resource);

}

public class XmlBeanFactory extends DefaultListableBeanFactory {

//这里为容器定义了一个默认使用的bean定义读取器

private final XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(this);

public XmlBeanFactory(Resource resource) throws BeansException {

this(resource, null);

}

//在初始化函数中使用读取器来对资源进行读取,得到bean定义信息。

public XmlBeanFactory(Resource resource, BeanFactory parentBeanFactory) throws BeansException {

super(parentBeanFactory);

this.reader.loadBeanDefinitions(resource);

}

我们在后面会看到读取器读取资源和注册bean定义信息的整个过程,基本上是和上下文的处理是一样的,从这里我们可以看到上下文和XmlBeanFactory这两种IOC容器的区别,BeanFactory往往不具备对资源定义的能力,而上下文可以自己完成资源定义,从这个角度上看上下文更好用一些。

仔细分析Spring BeanFactory的结构,我们来看看在BeanFactory基础上扩展出的ApplicationContext –我们最常使用的上下文。除了具备BeanFactory的全部能力,上下文为应用程序又增添了许多便利:

* 可以支持不同的信息源,我们看到ApplicationContext扩展了MessageSource

* 访问资源, 体现在对ResourceLoader和Resource的支持上面,这样我们可以从不同地方得到bean定义资源

* 支持应用事件,继承了接口ApplicationEventPublisher,这样在上下文中引入了事件机制而BeanFactory是没有的。

ApplicationContext允许上下文嵌套–通过保持父上下文可以维持一个上下文体系–这个体系我们在以后对Web容器中的上下文环境的分析中可以清楚地看到。对于bean的查找可以在这个上下文体系中发生,首先检查当前上下文,其次是父上下文,逐级向上,这样为不同的Spring应用提供了一个共享的bean定义环境。这个我们在分析Web容器中的上下文环境时也能看到。

ApplicationContext提供IoC容器的主要接口,在其体系中有许多抽象子类比如AbstractApplicationContext为具体的BeanFactory的实现,比如FileSystemXmlApplicationContext和ClassPathXmlApplicationContext提供上下文的模板,使得他们只需要关心具体的资源定位问题。当应用程序代码实例化FileSystemXmlApplicationContext的时候,得到IoC容器的一种具体表现–ApplicationContext,从而应用程序通过ApplicationContext来管理对bean的操作。

BeanFactory 是一个接口,在实际应用中我们一般使用ApplicationContext来使用IOC容器,它们也是IOC容器展现给应用开发者的使用接口。对应用程序开发者来说,可以认为BeanFactory和ApplicationFactory在不同的使用层面上代表了SPRING提供的IOC容器服务。下面我们具体看看通过FileSystemXmlApplicationContext是怎样建立起IOC容器的, 显而易见我们可以通过new来得到IoC容器:

Java代码

ApplicationContext = new FileSystemXmlApplicationContext(xmlPath);

ApplicationContext = new FileSystemXmlApplicationContext(xmlPath);

调用的是它初始化代码:

Java代码

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)

throws BeansException {

super(parent);

this.configLocations = configLocations;

if (refresh) {

//这里是IoC容器的初始化过程,其初始化过程的大致步骤由AbstractApplicationContext 来定义

refresh();

}

}

public FileSystemXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)

throws BeansException {

super(parent);

this.configLocations = configLocations;

if (refresh) {

//这里是IoC容器的初始化过程,其初始化过程的大致步骤由AbstractApplicationContext 来定义

refresh();

}

}

refresh的模板在AbstractApplicationContext:

Java代码

public void refresh() throws BeansException, IllegalStateException {

synchronized (this.startupShutdownMonitor) {

synchronized (this.activeMonitor) {

this.active = true;

}

// 这里需要子类来协助完成资源位置定义,bean载入和向IOC容器注册的过程

refreshBeanFactory();

…………

}

public void refresh() throws BeansException, IllegalStateException {

synchronized (this.startupShutdownMonitor) {

synchronized (this.activeMonitor) {

this.active = true;

}

// 这里需要子类来协助完成资源位置定义,bean载入和向IOC容器注册的过程

refreshBeanFactory();

............

}

这个方法包含了整个BeanFactory初始化的过程,对于特定的FileSystemXmlBeanFactory,我们看到定位资源位置由refreshBeanFactory()来实现:

在AbstractXmlApplicationContext中定义了对资源的读取过程,默认由XmlBeanDefinitionReader来读取:

Java代码

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {

// 这里使用XMLBeanDefinitionReader来载入bean定义信息的XML文件

XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

//这里配置reader的环境,其中ResourceLoader是我们用来定位bean定义信息资源位置的

///因为上下文本身实现了ResourceLoader接口,所以可以直接把上下文作为ResourceLoader传递给XmlBeanDefinitionReader

beanDefinitionReader.setResourceLoader(this);

beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

initBeanDefinitionReader(beanDefinitionReader);

//这里转到定义好的XmlBeanDefinitionReader中对载入bean信息进行处理

loadBeanDefinitions(beanDefinitionReader);

}

protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {

// 这里使用XMLBeanDefinitionReader来载入bean定义信息的XML文件

XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);

//这里配置reader的环境,其中ResourceLoader是我们用来定位bean定义信息资源位置的

///因为上下文本身实现了ResourceLoader接口,所以可以直接把上下文作为ResourceLoader传递给XmlBeanDefinitionReader

beanDefinitionReader.setResourceLoader(this);

beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));

initBeanDefinitionReader(beanDefinitionReader);

//这里转到定义好的XmlBeanDefinitionReader中对载入bean信息进行处理

loadBeanDefinitions(beanDefinitionReader);

}

转到beanDefinitionReader中进行处理:

Java代码

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {

Resource[] configResources = getConfigResources();

if (configResources != null) {

//调用XmlBeanDefinitionReader来载入bean定义信息。

reader.loadBeanDefinitions(configResources);

}

String[] configLocations = getConfigLocations();

if (configLocations != null) {

reader.loadBeanDefinitions(configLocations);

}

}

protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {

Resource[] configResources = getConfigResources();

if (configResources != null) {

//调用XmlBeanDefinitionReader来载入bean定义信息。

reader.loadBeanDefinitions(configResources);

}

String[] configLocations = getConfigLocations();

if (configLocations != null) {

reader.loadBeanDefinitions(configLocations);

}

}

而在作为其抽象父类的AbstractBeanDefinitionReader中来定义载入过程:

Java代码

public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {

//这里得到当前定义的ResourceLoader,默认的我们使用DefaultResourceLoader ResourceLoader resourceLoader = getResourceLoader();

………//如果没有找到我们需要的ResourceLoader,直接抛出异常

if (resourceLoader instanceof ResourcePatternResolver) {

// 这里处理我们在定义位置时使用的各种pattern,需要ResourcePatternResolver来

完成

try {

Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);

int loadCount = loadBeanDefinitions(resources);

return loadCount;

}

……..

}

else {

// 这里通过ResourceLoader来完成位置定位

Resource resource = resourceLoader.getResource(location);

// 这里已经把一个位置定义转化为Resource接口,可以供XmlBeanDefinitionReader 来使用了

int loadCount = loadBeanDefinitions(resource);

return loadCount;

}

}

public int loadBeanDefinitions(String location) throws BeanDefinitionStoreException {

//这里得到当前定义的ResourceLoader,默认的我们使用DefaultResourceLoader

ResourceLoader resourceLoader = getResourceLoader();

.........//如果没有找到我们需要的ResourceLoader,直接抛出异常

if (resourceLoader instanceof ResourcePatternResolver) {

// 这里处理我们在定义位置时使用的各种pattern,需要ResourcePatternResolver来完成

try {

Resource[] resources = ((ResourcePatternResolver) resourceLoader).getResources(location);

int loadCount = loadBeanDefinitions(resources);

return loadCount;

}

........

}

else {

// 这里通过ResourceLoader来完成位置定位

Resource resource = resourceLoader.getResource(location);

// 这里已经把一个位置定义转化为Resource接口,可以供XmlBeanDefinitionReader来使用了

int loadCount = loadBeanDefinitions(resource);

return loadCount;

}

}

当我们通过ResourceLoader来载入资源,别忘了了我们的GenericApplicationContext也实现了ResourceLoader接口:

Java代码

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

public Resource getResource(String location) {

//这里调用当前的loader也就是DefaultResourceLoader来完成载入

if (this.resourceLoader != null) {

return this.resourceLoader.getResource(location);

}

return super.getResource(location);

}

…….

}

public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {

public Resource getResource(String location) {

//这里调用当前的loader也就是DefaultResourceLoader来完成载入

if (this.resourceLoader != null) {

return this.resourceLoader.getResource(location);

}

return super.getResource(location);

}

.......

}

而我们的FileSystemXmlApplicationContext就是一个DefaultResourceLoader –GenericApplicationContext()通过DefaultResourceLoader:

Java代码

public Resource getResource(String location) {

//如果是类路径的方式,那需要使用ClassPathResource来得到bean文件的资源对象if (location.startsWith(CLASSPATH_URL_PREFIX)) {

return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());

}

else {

try {

// 如果是URL方式,使用UrlResource作为bean文件的资源对象

URL url = new URL(location);

return new UrlResource(url);

}

catch (MalformedURLException ex) {

// 如果都不是,那我们只能委托给子类由子类来决定使用什么样的资源对象了

return getResourceByPath(location);

}

}

}

public Resource getResource(String location) {

//如果是类路径的方式,那需要使用ClassPathResource来得到bean文件的资源对象

if (location.startsWith(CLASSPATH_URL_PREFIX)) {

return new ClassPathResource(location.substring(CLASSPATH_URL_PREFIX.length()), getClassLoader());

}

else {

try {

// 如果是URL方式,使用UrlResource作为bean文件的资源对象

URL url = new URL(location);

return new UrlResource(url);

}

catch (MalformedURLException ex) {

// 如果都不是,那我们只能委托给子类由子类来决定使用什么样的资源对象了

return getResourceByPath(location);

}

}

}

我们的FileSystemXmlApplicationContext本身就是是DefaultResourceLoader的实现类,他实现了以下的接口:

Java代码

protected Resource getResourceByPath(String path) {

if (path != null && path.startsWith("/")) {

path = path.substring(1);

}

//这里使用文件系统资源对象来定义bean文件

return new FileSystemResource(path);

}

protected Resource getResourceByPath(String path) {

if (path != null && path.startsWith("/")) {

path = path.substring(1);

}

//这里使用文件系统资源对象来定义bean文件

return new FileSystemResource(path);

}

这样代码就回到了FileSystemXmlApplicationContext中来,他提供了FileSystemResource来完成从文件系统得到配置文件的资源定义。这样,就可以从文件系统路径上对IOC配置文件进行加载–当然我们可以按照这个逻辑从任何地方加载,在Spring中我们看到它提供的各种资源抽象,比如ClassPathResource, URLResource,FileSystemResource等来供我们使用。上面我们看到的是定位Resource的一个过程,而这只是加载过程的一部分–我们回到AbstractBeanDefinitionReaderz中的loadDefinitions(resource)来看看得到代表bean文件的资源定义以后的载入过程,默认的我们使用XmlBeanDefinitionReader:

Java代码

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {

…….

try {

//这里通过Resource得到InputStream的IO流

InputStream inputStream = encodedResource.getResource().getInputStream();

try {

//从InputStream中得到XML的解析源

InputSource inputSource = new InputSource(inputStream);

if (encodedResource.getEncoding() != null) {

inputSource.setEncoding(encodedResource.getEncoding());

}

//这里是具体的解析和注册过程

return doLoadBeanDefinitions(inputSource, encodedResource.getResource());

}

finally {

//关闭从Resource中得到的IO流

inputStream.close();

}

}

………

}

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)

throws BeanDefinitionStoreException {

try {

int validationMode = getValidationModeForResource(resource);

//通过解析得到DOM,然后完成bean在IOC容器中的注册

Document doc = this.documentLoader.loadDocument(

inputSource, this.entityResolver, this.errorHandler, validationMode,

https://www.360docs.net/doc/c6907222.html,spaceAware);

return registerBeanDefinitions(doc, resource);

}

…….

}

public int loadBeanDefinitions(EncodedResource encodedResource) throws BeanDefinitionStoreException {

.......

try {

//这里通过Resource得到InputStream的IO流

InputStream inputStream = encodedResource.getResource().getInputStream();

try {

//从InputStream中得到XML的解析源

InputSource inputSource = new InputSource(inputStream);

if (encodedResource.getEncoding() != null) {

inputSource.setEncoding(encodedResource.getEncoding());

}

//这里是具体的解析和注册过程

return doLoadBeanDefinitions(inputSource, encodedResource.getResource());

}

finally {

//关闭从Resource中得到的IO流

inputStream.close();

}

}

.........

}

protected int doLoadBeanDefinitions(InputSource inputSource, Resource resource)

throws BeanDefinitionStoreException {

try {

int validationMode = getValidationModeForResource(resource);

//通过解析得到DOM,然后完成bean在IOC容器中的注册

Document doc = this.documentLoader.loadDocument(

inputSource, this.entityResolver, this.errorHandler, validationMode, https://www.360docs.net/doc/c6907222.html,spaceAware);

return registerBeanDefinitions(doc, resource);

}

.......

}

我们看到先把定义文件解析为DOM对象,然后进行具体的注册过程:

Java代码

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {

// 这里定义解析器,使用XmlBeanDefinitionParser来解析xml方式的bean定义文件- 现在的版本不用这个解析器了,使用的是XmlBeanDefinitionReader

if (this.parserClass != null) {

XmlBeanDefinitionParser parser =

(XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);

return parser.registerBeanDefinitions(this, doc, resource);

}

// 具体的注册过程,首先得到XmlBeanDefinitionReader,来处理xml的bean定义文件BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();

int countBefore = getBeanFactory().getBeanDefinitionCount();

documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

return getBeanFactory().getBeanDefinitionCount() - countBefore;

}

public int registerBeanDefinitions(Document doc, Resource resource) throws BeanDefinitionStoreException {

// 这里定义解析器,使用XmlBeanDefinitionParser来解析xml方式的bean定义文件- 现在的版本不用这个解析器了,使用的是XmlBeanDefinitionReader

if (this.parserClass != null) {

XmlBeanDefinitionParser parser =

(XmlBeanDefinitionParser) BeanUtils.instantiateClass(this.parserClass);

return parser.registerBeanDefinitions(this, doc, resource);

}

// 具体的注册过程,首先得到XmlBeanDefinitionReader,来处理xml的bean定义文件

BeanDefinitionDocumentReader documentReader = createBeanDefinitionDocumentReader();

int countBefore = getBeanFactory().getBeanDefinitionCount();

documentReader.registerBeanDefinitions(doc, createReaderContext(resource));

return getBeanFactory().getBeanDefinitionCount() - countBefore;

}

具体的在BeanDefinitionDocumentReader中完成对,下面是一个简要的注册过程来完成bean 定义文件的解析和IOC容器中bean的初始化

Java代码

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext;

logger.debug("Loading bean definitions");

Element root = doc.getDocumentElement();

BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);

preProcessXml(root);

parseBeanDefinitions(root, delegate);

postProcessXml(root);

}

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) { if (delegate.isDefaultNamespace(root.getNamespaceURI())) {

//这里得到xml文件的子节点,比如各个bean节点

NodeList nl = root.getChildNodes();

//这里对每个节点进行分析处理

for (int i = 0; i < nl.getLength(); i++) {

Node node = nl.item(i);

if (node instanceof Element) {

Element ele = (Element) node;

String namespaceUri = ele.getNamespaceURI();

if (delegate.isDefaultNamespace(namespaceUri)) {

//这里是解析过程的调用,对缺省的元素进行分析比如bean元素

parseDefaultElement(ele, delegate);

}

else {

delegate.parseCustomElement(ele);

}

}

}

} else {

delegate.parseCustomElement(root);

}

}

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //这里对元素Import进行处理

if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) {

importBeanDefinitionResource(ele);

}

else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) {

String name = ele.getAttribute(NAME_ATTRIBUTE);

String alias = ele.getAttribute(ALIAS_ATTRIBUTE);

getReaderContext().getReader().getBeanFactory().registerAlias(name, alias);

getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));

}

//这里对我们最熟悉的bean元素进行处理

else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {

//委托给BeanDefinitionParserDelegate来完成对bean元素的处理,这个类包含了具体的bean解析的过程。

// 把解析bean文件得到的信息放到BeanDefinition里,他是bean信息的主要载体,也是IOC容器的管理对象。

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

if (bdHolder != null) {

bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

// 这里是向IOC容器注册,实际上是放到IOC容器的一个map里

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

// 这里向IOC容器发送事件,表示解析和注册完成。

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

}

}

}

public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) { this.readerContext = readerContext;

logger.debug("Loading bean definitions");

Element root = doc.getDocumentElement();

BeanDefinitionParserDelegate delegate = createHelper(readerContext, root);

preProcessXml(root);

parseBeanDefinitions(root, delegate);

postProcessXml(root);

}

protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {

if (delegate.isDefaultNamespace(root.getNamespaceURI())) {

//这里得到xml文件的子节点,比如各个bean节点

NodeList nl = root.getChildNodes();

//这里对每个节点进行分析处理

for (int i = 0; i < nl.getLength(); i++) {

Node node = nl.item(i);

if (node instanceof Element) {

Element ele = (Element) node;

String namespaceUri = ele.getNamespaceURI();

if (delegate.isDefaultNamespace(namespaceUri)) {

//这里是解析过程的调用,对缺省的元素进行分析比如bean元素

parseDefaultElement(ele, delegate);

}

else {

delegate.parseCustomElement(ele);

}

}

}

} else {

delegate.parseCustomElement(root);

}

}

private void parseDefaultElement(Element ele, BeanDefinitionParserDelegate delegate) { //这里对元素Import进行处理

if (DomUtils.nodeNameEquals(ele, IMPORT_ELEMENT)) {

importBeanDefinitionResource(ele);

}

else if (DomUtils.nodeNameEquals(ele, ALIAS_ELEMENT)) {

String name = ele.getAttribute(NAME_ATTRIBUTE);

String alias = ele.getAttribute(ALIAS_ATTRIBUTE);

getReaderContext().getReader().getBeanFactory().registerAlias(name, alias);

getReaderContext().fireAliasRegistered(name, alias, extractSource(ele));

}

//这里对我们最熟悉的bean元素进行处理

else if (DomUtils.nodeNameEquals(ele, BEAN_ELEMENT)) {

//委托给BeanDefinitionParserDelegate来完成对bean元素的处理,这个类包含了具体的bean解析的过程。

// 把解析bean文件得到的信息放到BeanDefinition里,他是bean信息的主要载体,也是IOC容器的管理对象。

BeanDefinitionHolder bdHolder = delegate.parseBeanDefinitionElement(ele);

if (bdHolder != null) {

bdHolder = delegate.decorateBeanDefinitionIfRequired(ele, bdHolder);

// 这里是向IOC容器注册,实际上是放到IOC容器的一个map里

BeanDefinitionReaderUtils.registerBeanDefinition(bdHolder, getReaderContext().getRegistry());

// 这里向IOC容器发送事件,表示解析和注册完成。

getReaderContext().fireComponentRegistered(new BeanComponentDefinition(bdHolder));

}

}

}

我们看到在parseBeanDefinition中对具体bean元素的解析式交给BeanDefinitionParserDelegate来完成的,下面我们看看解析完的bean是怎样在IOC容器中注册的:

在BeanDefinitionReaderUtils调用的是:

Java代码

public static void registerBeanDefinition(

BeanDefinitionHolder bdHolder, BeanDefinitionRegistry beanFactory) throws BeansException {

// 这里得到需要注册bean的名字;

String beanName = bdHolder.getBeanName();

//这是调用IOC来注册的bean的过程,需要得到BeanDefinition

beanFactory.registerBeanDefinition(beanName, bdHolder.getBeanDefinition());

// 别名也是可以通过IOC容器和bean联系起来的进行注册

String[] aliases = bdHolder.getAliases();

if (aliases != null) {

for (int i = 0; i < aliases.length; i++) {

beanFactory.registerAlias(beanName, aliases[i]);

}

}

}

public static void registerBeanDefinition(

BeanDefinitionHolder bdHolder, BeanDefinitionRegistry beanFactory) throws BeansException {

// 这里得到需要注册bean的名字;

String beanName = bdHolder.getBeanName();

//这是调用IOC来注册的bean的过程,需要得到BeanDefinition

beanFactory.registerBeanDefinition(beanName, bdHolder.getBeanDefinition());

// 别名也是可以通过IOC容器和bean联系起来的进行注册

String[] aliases = bdHolder.getAliases();

if (aliases != null) {

for (int i = 0; i < aliases.length; i++) {

beanFactory.registerAlias(beanName, aliases[i]);

}

}

}

我们看看XmlBeanFactory中的注册实现:

Java代码

//———————————————————————

// 这里是IOC容器对BeanDefinitionRegistry接口的实现

//———————————————————————

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {

…..//这里省略了对BeanDefinition的验证过程

//先看看在容器里是不是已经有了同名的bean,如果有抛出异常。

Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);

if (oldBeanDefinition != null) {

if (!this.allowBeanDefinitionOverriding) {

………..

}

else {

//把bean的名字加到IOC容器中去

this.beanDefinitionNames.add(beanName);

}

//这里把bean的名字和Bean定义联系起来放到一个HashMap中去,IOC容器通过这个Map来维护容器里的Bean定义信息。

this.beanDefinitionMap.put(beanName, beanDefinition);

removeSingleton(beanName);

}

//---------------------------------------------------------------------

// 这里是IOC容器对BeanDefinitionRegistry接口的实现

//---------------------------------------------------------------------

public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) throws BeanDefinitionStoreException {

.....//这里省略了对BeanDefinition的验证过程

//先看看在容器里是不是已经有了同名的bean,如果有抛出异常。

Object oldBeanDefinition = this.beanDefinitionMap.get(beanName);

if (oldBeanDefinition != null) {

if (!this.allowBeanDefinitionOverriding) {

...........

}

else {

//把bean的名字加到IOC容器中去

this.beanDefinitionNames.add(beanName);

}

//这里把bean的名字和Bean定义联系起来放到一个HashMap中去,IOC容器通过这个Map来维护容器里的Bean定义信息。

this.beanDefinitionMap.put(beanName, beanDefinition);

removeSingleton(beanName);

}

这样就完成了Bean定义在IOC容器中的注册,就可被IOC容器进行管理和使用了。

从上面的代码来看,我们总结一下IOC容器初始化的基本步骤:

* 初始化的入口在容器实现中的refresh()调用来完成

* 对bean 定义载入IOC容器使用的方法是loadBeanDefinition,其中的大致过程如下:通过ResourceLoader来完成资源文件位置的定位,DefaultResourceLoader是默认的实现,同时上下文本身就给出了ResourceLoader的实现,可以从类路径,文件系统, URL等方式来定为资源位置。如果是XmlBeanFactory作为IOC容器,那么需要为它指定bean定义的资源,也就是说bean定义文件时通过抽象成Resource来被IOC容器处理的,容器通过BeanDefinitionReader来完成定义信息的解析和Bean信息的注册,往往使用的是XmlBeanDefinitionReader来解析bean的xml定义文件–实际的处理过程是委托给BeanDefinitionParserDelegate来完成的,从而得到bean的定义信息,这些信息在Spring中使用BeanDefinition对象来表示–这个名字可以让我们想到loadBeanDefinition,RegisterBeanDefinition这些相关的方法–他们都是为处理BeanDefinitin服务的,IoC容器解析得到BeanDefinition以后,需要把它在IOC容器中注册,这由IOC实现BeanDefinitionRegistry接口来实现。注册过程就是在IOC容器内部维护的一个HashMap来保存得到的BeanDefinition的过程。这个HashMap是IoC容器持有bean信息的场所,以后对bean的操作都是围绕这个HashMap来实现的。

* 然后我们就可以通过BeanFactory和ApplicationContext来享受到Spring IOC的服务了. 在使用IOC容器的时候,我们注意到除了少量粘合代码,绝大多数以正确IoC风格编写的应用程序代码完全不用关心如何到达工厂,因为容器将把这些对象与容器管理的其他对象钩在一起。基本的策略是把工厂放到已知的地方,最好是放在对预期使用的上下文有意义的地方,以及代码将实际需要访问工厂的地方。Spring本身提供了对声明式载入web应用程序用法的应用程序上下文,并将其存储在ServletContext中的框架实现。具体可以参见以后的文章。在使用Spring IOC容器的时候我们还需要区别两个概念:

Beanfactory 和Factory bean,其中BeanFactory指的是IOC容器的编程抽象,比如ApplicationContext,XmlBeanFactory等,这些都是IOC容器的具体表现,需要使用什么样的容器由客户决定但Spring为我们提供了丰富的选择。而FactoryBean只是一个可以在IOC容器中被管理的一个bean,是对各种处理过程和资源使用的抽象,Factory bean在需要时产生另一个对象,而不返回FactoryBean本省,我们可以把它看成是一个抽象工厂,对它的调用返回的是工厂生产的产品。所有的Factory bean都实现特殊的org.springframework.beans.factory.FactoryBean接口,当使用容器中factory bean的时候,该容器不会返回factory bean本身,而是返回其生成的对象。Spring包括了大部分的通用资源和服务访问抽象的Factory bean的实现,其中包括:

对JNDI查询的处理,对代理对象的处理,对事务性代理的处理,对RMI代理的处理等,这些我们都可以看成是具体的工厂,看成是SPRING为我们建立好的工厂。也就是说Spring通过使用抽象工厂模式为我们准备了一系列工厂来生产一些特定的对象,免除我们手工重复的

工作,我们要使用时只需要在IOC容器里配置好就能很方便的使用了。

现在我们来看看在Spring的事件机制,Spring中有3个标准事件,ContextRefreshEvent, ContextCloseEvent,RequestHandledEvent他们通过ApplicationEvent接口,同样的如果需要自定义时间也只需要实现ApplicationEvent接口,参照ContextCloseEvent的实现可以定制自己的事件实现:

Java代码

public class ContextClosedEvent extends ApplicationEvent {

public ContextClosedEvent(ApplicationContext source) {

super(source);

}

public ApplicationContext getApplicationContext() {

return (ApplicationContext) getSource();

}

}

public class ContextClosedEvent extends ApplicationEvent {

public ContextClosedEvent(ApplicationContext source) {

super(source);

}

public ApplicationContext getApplicationContext() {

return (ApplicationContext) getSource();

}

}

可以通过显现ApplicationEventPublishAware接口,将事件发布器耦合到ApplicationContext 这样可以使用ApplicationContext框架来传递和消费消息,然后在ApplicationContext中配置好bean就可以了,在消费消息的过程中,接受者通过实现ApplicationListener接收消息。比如可以直接使用Spring的ScheduleTimerTask和TimerFactoryBean作为定时器定时产生消息,具体可以参见《Spring框架高级编程》。

TimerFactoryBean是一个工厂bean,对其中的ScheduleTimerTask进行处理后输出,参考ScheduleTimerTask的实现发现它最后调用的是jre的TimerTask:

Java代码

public void setRunnable(Runnable timerTask) {

this.timerTask = new DelegatingTimerTask(timerTask);

}

public void setRunnable(Runnable timerTask) {

【智能路由器】ndpi深度报文分析源码框架

【智能路由器】ndpi深度报文分析源码 框架 某些需求可能会要求路由能精确的分析出流经路由的流量是属于什么类型,比如qq,facebook,支付宝、京东…… 正好,有这么一个基于opendpi框架的深度报文分析的工具——ndpi ndpi是在opendpi的基础上编写而来的协议分析工具。源代码编译后生成两个部分,一个是内核层的xt_ndpi.ko模块,用来实时分析流量,另一个是应用层的lib库,给ndpiReader这个工具提供库,用来分析抓包工具提供的文件或者底层网卡提供的数据包。 开发者必须为其想要分析的app的流量对应开发一个协议分析器,ndpi已经提供了不少现成的协议分析器,如http,QQ,twitter,vmware,yahoo,mysql,pplive等等。 本篇博客中作者arvik只叙述ndpi源码中形成内核层的xt_ndpi.ko模块的源码部分。 之后可能会写一篇介绍ndpi中已有的QQ协议分析器是怎么分析出OICQ协议以识别流量类型和一篇实战型依葫芦画瓢编写微信协议分析器的博客。 ndpi的分析过程: 当底层一帧数据被送入ndpi钩子的时候,流经结构大致如下: 1. 打包该数据帧,搜集l3、l4层报头信息 2. 查询链接跟踪(如果已被标识,则直接获取到该数据帧所属协议类型) 3. 从链接跟踪中未获取流量所属协议类型,则进入深度报文分析过程 4. 率先进行协议猜测,调用相应的协议分析器分析 5. 猜测协议错误、此时ndpi会分类遍历相关类型的协议分析器进行分析,直至分析出结果或遍历完所有相关的协议分析器 6. 将分析出的协议类型标记到链接跟踪中,以便下次可直接从连接跟踪中拿到协议类型 先来看内核模块代码: 几个重要结构 ndpi_detection_module_struct:各种协议分析器都将自己的信息都保存在该结构中 struct ndpi_detection_module_struct { NDPI_PROTOCOL_BITMASK detection_bitmask; //等价于struct xxx { uint32_t fds_bits[8]}; struct xxx dection; 其中fds_bits[8]每一位可代表一种协议,最多可代表256中协议 NDPI_PROTOCOL_BITMASK generic_http_packet_bitmask; u_int32_t current_ts;

Android源代码结构分析

目录 一、源代码结构 (2) 第一层次目录 (2) bionic目录 (3) bootloader目录 (5) build目录 (7) dalvik目录 (9) development目录 (9) external目录 (13) frameworks目录 (19) Hardware (20) Out (22) Kernel (22) packages目录 (22) prebuilt目录 (27) SDK (28) system目录 (28) Vendor (32)

一、源代码结构 第一层次目录 Google提供的Android包含了原始Android的目标机代码,主机编译工具、仿真环境,代码包经过解压缩后,第一级别的目录和文件如下所示: . |-- Makefile (全局的Makefile) |-- bionic (Bionic含义为仿生,这里面是一些基础的库的源代码) |-- bootloader (引导加载器),我们的是bootable, |-- build (build目录中的内容不是目标所用的代码,而是编译和配置所需要的脚本和工具) |-- dalvik (JAVA虚拟机) |-- development (程序开发所需要的模板和工具) |-- external (目标机器使用的一些库) |-- frameworks (应用程序的框架层) |-- hardware (与硬件相关的库) |-- kernel (Linux2.6的源代码) |-- packages (Android的各种应用程序) |-- prebuilt (Android在各种平台下编译的预置脚本) |-- recovery (与目标的恢复功能相关) `-- system (Android的底层的一些库)

Mina2源码分析

Mina2.0框架源码剖析(一) 整个框架最核心的几个包是:org.apache.mina.core.service, org.apache.mina.core.session, org.apache.mina.core.polling以及 org.apache.mina.transport.socket。 这一篇先来看org.apache.mina.core.service。第一个要说的接口是IoService,它是所有IoAcceptor和IoConnector的基接口.对于一个IoService,有哪些信息需要我们关注呢?1)底层的元数据信息TransportMetadata,比如底层的网络服务提供者(NIO,ARP,RXTX等),2)通过这个服务创建一个新会话时,新会话的默认配置IoSessionConfig。3)此服务所管理的所有会话。4)与这个服务相关所产生的事件所对应的监听者(IoServiceListener)。5)处理这个服务所管理的所有连接的处理器(IoHandler)。6)每个会话都有一个过滤器链(IoFilterChain),每个过滤器链通过其对应的IoFilterChainBuilder来负责构建。7)由于此服务管理了一系列会话,因此可以通过广播的方式向所有会话发送消息,返回结果是一个WriteFuture集,后者是一种表示未来预期结果的数据结构。8)服务创建的会话(IoSession)相关的数据通过IoSessionDataStructureFactory来提供。9)发送消息时有一个写缓冲队列。10)服务的闲置状态有三种:读端空闲,写端空闲,双端空闲。11)还提供服务的一些统计信息,比如时间,数据量等。 IoService这个服务是对于服务器端的接受连接和客户端发起连接这两种行为的抽象。 再来从服务器看起,IoAcceptor是IoService 的子接口,它用于绑定到指定的ip和端口,从而接收来自客户端的连接请求,同时会fire相应的客户端连接成功接收/取消/失败等事件给自己的IoHandle去处理。当服务器端的Accpetor从早先绑定的ip和端口上取消绑定时,默认是所有的客户端会话会被关闭,这种情况一般出现在服务器挂掉了,则客户端收到连接关闭的提示。这个接口最重要的两个方法是bind()和unbind(),当这两个方法被调用时,服务端的连接接受线程就启动或关闭了。 再来看一看客户端的连接发起者接口IoConnector,它的功能和IoAcceptor基本对应的,它用于尝试连接到服务器指定的ip和端口,同时会fire相应的客户端连接事件给自己的IoHandle去处理。当connet方法被调用后用于连接服务器端的线程就启动了,而当所有的连接尝试都结束时线程就停止。尝试连接的超时时间可以自行设置。Connect方法返回的结果是ConnectFuture,这和前面说的WriteFuture类似,在后面会有一篇专门讲这个模式的应用。 前面的IoAcceptor和IoConnector就好比是两个负责握手的仆人,而真正代表会话的实际I/O操作的接口是IoProcessor,它对现有的Reactor模式架构的Java NIO框架继续做了一层封装。它的泛型参数指明了它能处理的会话类型。接口中最重要的几个方法,add用于将指定会话加入到此Processor中,让它负责处理与此会话相关的所有I/O操作。由于写操作会有一个写请求队列,flush就用于对指定会话的写请求队列进行强制刷数据。remove方法用于从此Processor中移除和关闭指定会话,

gh0st源码分析,整理笔记

MICROSOFT SPEECH SDK 5.1\INCLUDE MICROSOFT SPEECH SDK 5.1\LIB 以上两个目录是教程里面提到的,可以不使用,一样可以编译 第一节课 新建MFC工程,单文档模式,基类用CListView,其余默认即可 打开gh0stView.cpp找到void CGh0stView::OnInitialUpdate()函数 新建一个结NONCLIENTMETRICS ncm; NONCLIENTMETRICS这个结构就包含了非客户区的一些属性 对ncm变量进行初始化memset(&ncm, 0, sizeof(NONCLIENTMETRICS)); 对这个结构的成员函数进行设置 ncm.cbSize = sizeof(NONCLIENTMETRICS); //指定了ncm的大小 使用宏 VERIFY(::SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(NONCLIENTMETRICS), &ncm,0)); 其目的是方便调试,在Debug版本中,如果计算的表达式为0则中断程序,并打印出错误信息,如果在Release版本中,出现表达式为0的时候,则不做任何的处理,当没有发生::SystemParametersInfo调用系统函数,查询或是设置系统参数,或是修改用户的一个外观,返回值是一个BOOL类型 第一个参数是获取非客户区参数 第二个参数是整个的非客户区结构的大小 第三个参数是将获得到的信息保存在ncm这个地址中 第四个参数由于是为了获取信息写0即可,如果是设置信息为目的,就需要换成其它 参考MSDN 第二节课 在gh0stView.h中声明一个私有成员变量 公有成员可以被所有类访问 受保护成员只能在类内部或其子类可以访问 私有成员只能在类内部访问,其子类是不可以访问的 private: CListCtrl* m_pListCtrl; 私有的列表控件的指针,为什么要声明这个呢,我们之前提到了基类是CListView,因此在这个里声明了一个指针 CPP是执行文件,H是头文件 接下来对我们在CPP文件中声明的私有成员变量进行赋值 m_pListCtrl=&GetListCtrl(); GetListCtrl()这个函数的原型是 CListView::GetListCtrl CListCtrl& GetListCtrl() const; 得到一个和视图相关联的一个列表控件的引用 引用的使用方法:引用相当于是一个别名,周瑜和周公谨是一个人,引用和变量也相当于是

JQUERY源码解析(架构与依赖模块)

jQuery设计理念 引用百科的介绍: jQuery是继prototype之后又一个优秀的Javascript框架。它是轻量级的js库,它兼容CSS3,还兼容各种浏览器(IE 6.0+,FF1.5+,Safari 2.0+,Opera9.0+),jQuery2.0及后续版本将不再支持IE6/7/8浏览器。jQuery使用户能更方便地处理HTML(标准通用标记语言下的一个应用)、events、实现动画效果,并且方便地为网站提供AJAX交互。jQuery还有一个比较大的优势是,它的文档说明很全,而且各种应用也说得很详细,同时还有许多成熟的插件可供选择。jQuery能够使用户的html页面保持代码和html内容分离,也就是说,不用再在html里面插入一堆js来调用命令了,只需定义id即可。 The Write Less,Do More(写更少,做更多),无疑就是jQuery的核心理念,简洁的API、优雅的链式、强大的查询与便捷的操作。从而把jQuery打造成前端世界的一把利剑,所向披靡! 简洁的API: 优雅的链式: 强大的选择器: 便捷的操作:

为什么要做jQuery源码解析? 虽然jQuery的文档很完善,潜意识降低了前端开发的入门的门槛,要实现一个动画随手拈来,只要简单的调用一个animate方法传递几个执行的参数即可,但如果要我们自己实现一个定制的动画呢?我们要考虑的问题太多太多了,浏览器兼容、各种属性的获取、逻辑流程、性能等等,这些才是前端开发的基础核心。 如果我们只知道使用jQuery,而不知道其原理,那就是“知其然,而不知其所以然”,说了这么多,那就赶快跟着慕课网进入“高大上”之旅吧,深入来探究jQuery的内部架构! jQuery整体架构 任何程序代码不是一开始就复杂的,成功也不是一躇而蹴的,早期jQuery的作者John Resig 在2005年提议改进Prototype的“Behaviour”库时,只是想让其使用更简单才发布新的jQuery 框架。起初John Resig估计也没料想jQuery会如此的火热。我们可以看到从发布的第一个1. 0开始到目前最新的2.1.1其代码膨胀到了9000多行,它兼容CSS3,还兼容各种浏览器,jQu ery使用户能更方便地处理DOM、事件、实现动画效果,并且方便地为网站提供AJAX交互。 1、最新jQuery2.1.1版本的结构: 代码请查看右侧代码编辑器(1-24行) 2、jQuery的模块依赖网: (单击图片可放大)

APP项目功能和架构分析

APP项目功能和架构分析 2016 年2 月12 日提交 提交人: 电话: Email: Wechat: Reverb 项目功能和架构分析 (1) 项目目标............................................................................................................................................... (3) 平台类型 (3) 项目周期: (3) 交付内容............................................................................................................................................... (4) 功能描述............................................................................................................................................... ...5 (5) (7) (9) 开发计划............................................................................................................................................... .10 付款计划............................................................................................................................................... .11 团队项目经验介绍 (12) 项目可能用到的技术内容 (15) 项目目标 平台类型 Web 网站 iOS 端

Ceilometer源码分析

Ceilometer项目源码架构 ceilometer主要概念 sample:采样数据是每个采集时间点上meter对应的值; statistics:一般是统计学上某个周期内,meter对应的值(平均值之类); resource:是被监控的资源对象,这个可以是一台虚拟机,一台物理机或者一块云硬盘;alarm:是ceilometer的报警系统,可以通过阈值或者组合条件报警,并设置报警时触发的action,alarm的实现模型有两种,即单例报警系统和分布式报警系统; meter:被跟踪资源的测量值。一个实例有很多的计量值,比如实例运行时长、CPU使用时间、请求磁盘的数量等。在Ceilometer中有三种计量值: Cumulative:累计的,随着时间增长(如磁盘读写); Gauge:计量单位,离散的项目(如浮动IP,镜像上传)和波动的值(如对象存储数值); Delta:增量,随着时间的改变而增加的值(如带宽变化); Centralagent:运行在OpenStack架构中中央管理节点上用来测量和发送监控结果到收集器的服务; Computeagent:运行再OpenStack架构中计算节点上的服务,用来测量和发送监控结果到搜集器中; APIserver:Ceilometer的HTTPRESTAPI服务; collector:运行在OpenStack架构中的服务,用来监控来自其他OpenStack组件和监控代理发送来的通知,并且将其存入数据库中; ceilometer中的服务组件 需要说明这里是针对icehouse版对ceilometer模块进行源码解析。根据配置文件setup.cfg以及/ceilometer/cli.py可以知道,运行在ceilometer中的服务组件有如下所示: ceilometer-api:ceilometer.cli:api ceilometer-agent-central:ceilometer.cli:agent_central ceilometer-agent-compute:ceilometer.cli:agent_compute ceilometer-agent-notification:ceilometer.cli:agent_notification ceilometer-send-sample:ceilometer.cli:send_sample ceilometer-dbsync:ceilometer.cli:storage_dbsync ceilometer-expirer:ceilometer.cli:storage_expirer ceilometer-collector:ceilometer.cli:collector_service ceilometer-alarm-evaluator:ceilometer.cli:alarm_evaluator ceilometer-alarm-notifier:ceilometer.cli:alarm_notifier ceilometer监控数据采集机制 这里借助网上获取的一副图片来说明ceilometer监控数据的采集机制(对其作者表示感谢):

传奇源码分析---框架

传奇源码分析---框架 标签:游戏源码框架 2013-10-31 14:09 2253人阅读评论(1) 收藏举报分类: 游戏源码(4) 版权声明:本文为博主原创文章,未经博主允许不得转载。 最近看游戏源码,对于大一点的源码,完全不知道怎么开始,太庞大了,网狐的源码都达到了1G多了,vc6.0打开直接卡死,不得不说vs2010还是很不错的。大的源码看不懂,最后去看最小的源码,传奇服务端源码。 1.找到winmain函数(GameSvr.cpp),InitApplication()函数注册窗口回调函数MainWndProc(MainWndProc.cpp). InitInstance()函数主要对窗口编程。 2.开启服务回调函数调用OnCommand(),创建了一个线程InitializingServer;在线程里面调用ConnectToServer()函数。ConnectToServer()里面将监听套接字(没看全局变量,推测的)注册到窗口回调函数里面,消息的ID为:_IDM_CLIENTSOCK_MSG然后,自己连接这个服务器,到此ConnectToServer()函数结束。 3.由于上一步,收到了_IDM_CLIENTSOCK_MSG,窗口函数调用OnClientSockMsg()。这个函数里面创建了ProcessLogin、ProcessUserHuman、ProcessMonster、ProcessNPC 线程,然后通过调用InitServerSocket创建CreateIOCPWorkerThread完成端口。继续调用InitThread创建AcceptThread线程,OK到此程序基本框架搭建起来了。CreateIOCPWorkerThread里面创建了完成端口工作者线程ServerWorkerThread。 到此服务器的基本架构搭建起来了。 直接看图吧,思路清晰一些。

如何看懂源代码--(分析源代码方法)

如何看懂源代码--(分析源代码方法) 4 推 荐 由于今日计划着要看Struts 开源框架的源代码 昨天看了一个小时稍微有点头绪,可是这个速度本人表示非常不满意,先去找了下资 料, 觉得不错... 摘自(繁体中文 Traditional Chinese):http://203.208.39.132/translate_c?hl=zh-CN&sl=en&tl=zh-CN&u=http://ww https://www.360docs.net/doc/c6907222.html,/itadm/article.php%3Fc%3D47717&prev=hp&rurl=https://www.360docs.net/doc/c6907222.html,&usg=AL kJrhh4NPO-l6S3OZZlc5hOcEQGQ0nwKA 下文为经过Google翻译过的简体中文版: 我们在写程式时,有不少时间都是在看别人的代码。 例如看小组的代码,看小组整合的守则,若一开始没规划怎么看,就会“噜看噜苦(台语)”不管是参考也好,从开源抓下来研究也好,为了了解箇中含意,在有限的时间下,不免会对庞大的源代码解读感到压力。网路上有一篇关于分析看代码的方法,做为程式设计师的您,不妨参考看看,换个角度来分析。也能更有效率的解读你想要的程式码片段。 六个章节: ( 1 )读懂程式码,使心法皆为我所用。( 2 )摸清架构,便可轻松掌握全貌。( 3 )优质工具在手,读懂程式非难事。( 4 )望文生义,进而推敲组件的作用。( 5 )找到程式入口,再由上而下抽丝剥茧。( 6 )阅读的乐趣,透过程式码认识作者。 程式码是别人写的,只有原作者才真的了解程式码的用途及涵义。许多程式人心里都有一种不自觉的恐惧感,深怕被迫去碰触其他人所写的程式码。但是,与其抗拒接收别人的程式码,不如彻底了解相关的语言和惯例,当成是培养自我实力的基石。 对大多数的程式人来说,撰写程式码或许是令人开心的一件事情,但我相信,有更多人视阅读他人所写成的程式码为畏途。许多人宁可自己重新写过一遍程式码,也不愿意接收别人的程式码,进而修正错误,维护它们,甚至加强功能。 这其中的关键究竟在何处呢?若是一语道破,其实也很简单,程式码是别人写的,只有原作者才真的了解程式码的用途及涵义。许多程式人心里都有一种不自觉的恐惧感,深怕被迫去碰触其他人所写的程式码。这是来自于人类内心深处对于陌生事物的原始恐惧。 读懂别人写的程式码,让你收获满满 不过,基于许多现实的原因,程式人时常受迫要去接收别人的程式码。例如,同事离职了,必须接手他遗留下来的工作,也有可能你是刚进部门的菜鸟,而同事经验值够了,升级了,风水轮流转,一代菜鸟换菜鸟。甚至,你的公司所承接的专案,必须接手或是整合客户前一个厂商所遗留下来的系统,你们手上只有那套系统的原始码(运气好时,还有数量不等的文件)。 诸如此类的故事,其实时常在程式人身边或身上持续上演着。许多程式人都将接手他人的程式码,当做一件悲惨的事情。每个人都不想接手别人所撰写的程式码,因为不想花时间去探索,宁可将生产力花在产生新的程式码,而不是耗费在了解这些程式码上。

分析 JUnit 框架源代码

分析JUnit 框架源代码 理解JUnit 测试框架实现原理和设计模式 2009 年5 月31 日 本文细致地描述了JUnit 的代码实现,在展示代码流程UML 图的基础上,详细分析JUnit 的内部实现代码的功能与机制,并在涉及相关设计模式的地方结合代码予以说明。另外,分析过程还涉及Reflection 等Java 语言的高级特征。 概述 在测试驱动的开发理念深入人心的今天,JUnit 在测试开发领域的核心地位日渐稳定。不仅Eclipse 将JUnit 作为默认的IDE 集成组件,而且基于JUnit 的各种测试框架也在业内被广泛应用,并获得了一致好评。目前介绍JUnit 书籍文章虽然较多,但大多数是针对JUnit 的具体应用实践,而对于JUnit 本身的机制原理,只是停留在框架模块的较浅层次。 本文内容完全描述JUnit 的细致代码实现,在展示代码流程UML 图的基础上,详细分析JUnit 的内部实现代码的功能与机制,并在涉及相关设计模式的地方结合代码予以说明。另外,分析过程还涉及Reflection 等Java 语言的高级特征。 本文的读者应该对JUnit 的基本原理及各种设计模式有所了解,主要是面向从事Java 相关技术的设计、开发与测试的人员。对于C++,C# 程序员也有很好的借鉴作用。 回页首 Junit 简介 JUnit 的概念及用途

JUnit 是由Erich Gamma 和Kent Beck 编写的一个开源的单元测试框架。它属于白盒测试,只要将待测类继承TestCase 类,就可以利用JUnit 的一系列机制进行便捷的自动测试了。 JUnit 的设计精简,易学易用,但是功能却非常强大,这归因于它内部完善的代码结构。Erich Gamma 是著名的GOF 之一,因此JUnit 中深深渗透了扩展性优良的设计模式思想。JUnit 提供的API 既可以让您写出测试结果明确的可重用单元测试用例,也提供了单元测试用例成批运行的功能。在已经实现的框架中,用户可以选择三种方式来显示测试结果,并且显示的方式本身也是可扩展的。 JUnit 基本原理 一个JUnit 测试包含以下元素: 表 1. 测试用例组成 操作步骤: 将B 通过命令行方式或图形界面选择方式传递给R,R 自动运行测试,并显示结果。 JUnit 中的设计模式体现 设计模式(Design pattern)是一套被反复使用的、为众人所知的分类编目的代码设计经验总结。使用设计模式是为了可重用和扩展代码,增加代码的逻辑性和可靠性。设计模式的出现使代码的编制真正工程化,成为软件工程的基石。 GoF 的《设计模式》一书首次将设计模式提升到理论高度,并将之规范化。该书提出了23 种基本设计模式,其后,在可复用面向对象软件的发展过程中,新的设计模式亦不断出现。 软件框架通常定义了应用体系的整体结构类和对象的关系等等设计参数,以便于具体应用实现者能集中精力于应用本身的特定细节。因此,设计模式有助于对框架结构的理解,成熟的框架通常使用了多种设计模式,JUnit 就是其中的优秀代表。设计模式是JUnit 代码的精髓,没有设计模式,JUnit 代码无法达到在小代码量下的高扩展性。总体上看,有三种设计模式在JUnit 设计中得到充分体现,分别为Composite 模式、Command 模式以及Observer 模式。

Yarn框架代码详细分析V0.3

Yarn框架代码详细分析V0.3 阿里巴巴封神2012年1月https://www.360docs.net/doc/c6907222.html,/blog 目录 一、yarn简单介绍 (2) 1.1、概述 (3) 1.2、YARN的优势 (4) 1.3、新框架下的软件设计模式 (4) 1.4、HADOOP 2.0.0- alpha工程结构 (4) 二、yarn模块详细分析 (5) 2.1、接口 (5) 2.2、各大模块分析 (6) 2.2.1、RM (6) 2.2.2、NM (8) 2.2.3、MRAppMaster (9) 2.2.4、MRYarnChild (10) 三、功能点详细分析 (11) 3.1、Jobhistory机制 (11) 3.1.1.NM收集日志 (11) 3.1.2.MRAppMaster收集JobHistory (12) 3.1.3.JobHistoryServer (12) 3.2、RM调度器 (13) 3.2.1、简述 (13) 3.2.2、FairScheduler代码分析 (14) 3.2.3、FairScheduler资源预分配 (14) 3.2.4、FairScheduler抢占资源 (15) 3.2.5、FairScheduler container分配 (15) 3.3、MRAppMaster分配器 (17) 3.3.1、代码分析 (17) 3.3.2、任务周期管理及资源分配 (17) 3.3、shuffle (19) 3.5、NM的资源下载 (20)

版本介绍 V0.1 yarn简单介绍、yarn模块详细分析、Jobhistory机制介绍V0.2 添加RM调度器、MRAppMaster分配器 V0.3 完善调度器的描述,添加一些细节描述

MapReduce源码分析完整版

一MapReduce概述 Map/Reduce是一个用于大规模数据处理的分布式计算模型,它最初是由Google工程师设计并实现的,Google已经将它完整的MapReduce论文公开发布了。其中对它的定义是,Map/Reduce是一个编程模型(programming model),是一个用于处理和生成大规模数据集(processing and generating large data sets)的相关的实现。用户定义一个map函数来处理一个key/value对以生成一批中间的key/value对,再定义一个reduce函数将所有这些中间的有着相同key的values合并起来。很多现实世界中的任务都可用这个模型来表达。 二MapReduce工作原理 1 Map-Reduce Map-Reduce框架的运作完全基于对,即数据的输入是一批对,生成的结果也是一批对,只是有时候它们的类型不一样而已。Key和value的类由于需要支持被序列化(serialize)操作,所以它们必须要实现Writable接口,而且key的类还必须实现WritableComparable接口,使得可以让框架对数据集的执行排序操作。 一个Map-Reduce任务的执行过程以及数据输入输出的类型如下所示: Map: ——> list Reduce:> ——> 2例子 下面通过一个的例子来详细说明这个过程。WordCount是Hadoop自带的一个例子,目标是统计文本文件中单词的个数。假设有如下的两个文本文件来运行WorkCount程序:Hello World Bye World Hello Hadoop GoodBye Hadoop 2.1 map数据输入 Hadoop针对文本文件缺省使用LineRecordReader类来实现读取,一行一个key/value对,key取偏移量,value为行内容。 如下是map1的输入数据: Key1 Value1 0 Hello World Bye World 如下是map2的输入数据: Key1Value1 0 Hello Hadoop GoodBye Hadoop 2.2 map输出/combine输入 如下是map1的输出结果

php框架ThinkPHP代码分析核心解析

前言 TP的手册相当多,其实不必再出这样的贴子,论技术,我也是菜鸟一个,同时也在学习当中。看到论坛上多了不少新朋友,不少在抱怨手册看不懂,那我就姑且抛砖引玉,尝试与新朋友们更简单地、手把手地进入TP的应用中去。讲解过程中有错的地方,大家帮忙指正。 这个系列,初步定下的目标为,从零开始,以TP示例中心中的Form为例进行讲解,以实践为主,理论为辅,将TP的最基本内容逛一遍,至少让我们一起学会如何进行最简单的对数据进行查、增、改、删操作并输出到模板。 由于我们说的是循序渐进,所以我用步骤式来说明,只要一步一步跟着做,相信聪明的你在使用过程中就会明白TP的应用了。 注意:以下的步骤,仅仅是TP灵活的布署方式其中一种,实际开发中可以根据自己的情况去另行设定。至于为什么那样做,我们会在最后再作总结,我觉得先实操然后再进行说明比较容易明白。以下不再重复解释。 一快速开始一个项目 名词解释: 项目:你要开发的系统,称之为项目。 入口文件:你可以理解为这个项目的唯一的一道门,以后所有的操作都会通过这道门去执行处理。不必理会什么意思,你甚至可以先把它看成是index.php就是入口文件 TP: ThinkPHP框架的简称 1 下载TP1.5正式版 2 拟好你的项目名称,我们这里以 Myapp 为项目名称 3 在www根目录下,将TP框架所有文件全部复制过去,文件夹名称是ThinkPHP 4 与ThinkPHP同级新建一个文件夹,起名为 Myapp,也就是项目名称 5 在www根目录下,创建一个PHP文件,起名index.php,这就是入口文件 入口文件index.php代码: run(); ?>

Activity Manager框架解析

Activity Manager框架解析 ActivityManager在操作系统中有重要的作用,本文利用操作系统源码,逐步理清ActivityManager的框架,并从静态类结构图和动态序列图两个角度分别进行剖析,从而帮助开发人员加强对系统框架及进程通信机制的理解。 ActivityManager的源码结构图: ActivityManager的作用 ActivityManager的功能是与系统中所有运行着的Activity交互提供了接口,主要的接口围绕着运行中的进程信息,任务信息,服务信息等。比如函数getRunningServices()的源码是:public List getRunningServices(int maxNum) throws SecurityException {

try { return (List)ActivityManagerNative.getDefault() .getServices(maxNum, 0); } catch (RemoteException e) { // System dead, we will be dead too soon! return null; } } 从源码中可以看到ActivityManager的大多数功能都是调用了ActivityManagerNative类接口 来完成的,因此,我们寻迹来看ActivityManagerNative的代码,并以此揭示ActivityManager的 整体框架。 ActivityManager的静态类图 通过源码,可以发现ActivityManagerNative类的继承关系如下:public abstract class ActivityManagerNative extends Binder implements IactivityManager继承自Binder类,同时实现了IActivityManager接口。同样的,我们继续沿Binder和IActivityManager上溯,整 理出如下图所示的类结构图。 在这张图中,绿色的部分是在SDK中开放给应用程序开发人员的接口,蓝色的部分是一个典型的Proxy模式,红色的部分是底层的服务实现,是真正的动作执行者。这里的一个核心思想是Proxy模式,我们接下来对此模式加以介绍。

struts2源代码分析(个人觉得非常经典)

本章讲述Struts2的工作原理。 读者如果曾经学习过Struts1.x或者有过Struts1.x的开发经验,那么千万不要想当然地以为这一章可以跳过。实际上Struts1.x与Struts2并无我们想象的血缘关系。虽然Struts2的开发小组极力保留S truts1.x的习惯,但因为Struts2的核心设计完全改变,从思想到设计到工作流程,都有了很大的不同。 Struts2是Struts社区和WebWork社区的共同成果,我们甚至可以说,Struts2是WebWork的升级版,他采用的正是WebWork的核心,所以,Struts2并不是一个不成熟的产品,相反,构建在We bWork基础之上的Struts2是一个运行稳定、性能优异、设计成熟的WEB框架。 本章主要对Struts的源代码进行分析,因为Struts2与WebWork的关系如此密不可分,因此,读者需要下载xwork的源代码,访问https://www.360docs.net/doc/c6907222.html,/xwork/download.action即可自行下载。 下载的Struts2源代码文件是一个名叫struts-2.1.0-src.zip的压缩包,里面的目录和文件非常多,读者可以定位到struts-2.1.0-src"struts-2.0.10"src"core"src"main"java目录下查看Struts2的源文件,如图14所示。 (图14) 主要的包和类 Struts2框架的正常运行,除了占核心地位的xwork的支持以外,Struts2本身也提供了许多类,这些类被分门别类组织到不同的包中。从源代码中发现,基本上每一个Struts2类都访问了WebWork提供的功能,从而也可以看出Struts2与WebWork千丝万缕的联系。但无论如何,Struts2的核心功能比如将请求委托给哪个Action处理都是由xwork完成的,Struts2只是在WebWork的基础上做了适当的简化、加强和封装,并少量保留Struts1.x中的习惯。 以下是对各包的简要说明: 包名说明

JForum框架源码分析详解

JForum框架结构和主要配置文件说明 关键字: jforum二次开发 学习JForum总结: 环境搭建:TOMCAT + MYSQL 第一步:安装部署 1、去https://www.360docs.net/doc/c6907222.html,/download.jsp网站下载jforum的发布包。 2、安装mysql数据库。为了解决论坛出现的中文乱码问题,可以通过手动修改配置文件或者在安装mysql时设置编码为utf8, 可以避免页面中显示乱码。安装好mysql后,进入>mysql状态输入: CREATE DATABASE JForum DEFAULT CHARACTER SET utf8 COLLAT E utf8_general_ci; 3、将jforum发布包拷贝到D:\apache-tomcat-6.0.16\webapps目录下即可。安装配置jforum可以通过两种方式实现,手动修改配置文件或者通过页面提示信息安装步骤。为避免出错,我们选取自动安装的方式进行。 启动TOMCAT服务后,通过浏览器访问 http://localhost:8080/jforum/install.jsp依照提示信息配置好所需信息, 一路next。安装完成之后访问http://localhost:8080/jforum将会出现论坛首页。 第二步:分析JFORUM框架中配置文件 1、 zh_CN.properties文件中配置页面中显示的中文常用汉字。cmd下可以通 过native2ascii -reverse zh_CN.properties a.properties命令对其反编码,开发者可以配置自己需要的页面中需要显示常量信息,编辑保存后再通过 native2ascii a.propertieszh_CN.properties 在编码回ascii。 2、 modulesMapping.properties文件中描述了模块名与实现该模块功能的 java类的对应关系。 3、 locales.properties文件在SystemGlobals.properties文件中被配置加载,locales.properties 文件中配置各种国家支持的语言。locales.properties 文件在ConfigAction.java中被读取。 4、 webapps\jforum\WEB-INF\config\database\generic\generic_queries.s ql 文件中配置数据库查询语句而该sql文件又在SystemGlobals.properties 文件中被配置加载。 SystemGlobals.properties文件中配置的变量信息在ConfigKeys.java类文件中配置对应的常量字符串。可以通过 String q = SystemGlobals.getSql("XXX")方式去获得需要的配置好的sql语句。 I18n.getMessage("XXX")方式可以在页面中或者类中获得zh_CN.properties 配置文件中配置的中文常量 5、 templatesMapping.properties配置文件配置相关的页面对应文件。templatesMapping.properties文件中配置的变量信息在TemplateKeys.java类文件中配置对应的常量字符串。 6、 jforum-custom.conf配置文件为有关数据库信息的文件,可以通过手动去

gzd-java集合框架的一些源码类型分析

集合框架 HashMap、HashTable、LinkedHashMap 1、HashMap与HashTable的异同。 →都实现了Map接口 →HashTable继承自dictionary类,而HashMap是Java1.2引进的Map interface 的一个实现。 →HashMap允许将null作为Key或者Value,但HashTable不可以 →HashMap将HashTable的Contains方法去掉了,改成了ContainsKey和ContainsValue. →最大的不同是:HashTable方法是synchronize的,在多线程访问HashTable 时,不需要自己为他的方法实现同步,而HashMap就必须为之同步. 注:HasHTanle所有的方法都是synchronized的,下图只是其中之一。

Collection和map →Collection一组对立的u元素,这些元素都服从某些规则,List必须保持元素的顺序性,而Set不可以有重复的元素 →collection 对象之间没有指定的顺序,也可以重复元素 →set 对象之间没有指定的顺序,但不可以有重复元素 →List 对象之间有指定的顺序,因为引入了角标,可以有重复的元素 →Map概念其实很很清晰,其实也可以把Map当成Collection的一个元素,只不过这个元素是一个键值对!但是这样就太混乱了,也太笨拙了,所以把Map作为单个的一个概念,似乎更加清晰,而且Map也很容易扩展,value 的值可以是另一个Map,如此下去,甚至无线扩展。 (注:List 、Set、Map共同的实现基础是Object数组) →除了四个历史集合类外,Java 2 框架还引入了六个集合实现,如下表所示。 接口实现历史集合类 Set HashSet TreeSet

相关主题
相关文档
最新文档