分类目录归档:Java开发

xml配置文件读取

        String filePath = Thread.currentThread().getContextClassLoader().getResource("MemCachedConfig.xml").getPath().substring(1);
        File file = new File(filePath.replaceAll("%20"," "));
        try{
            if(file.exists()){ //如果可以成功加载配置文件
                SAXReader sr = new SAXReader();
                Document doc = sr.read(file);
                Element Root = doc.getRootElement(); //获得根节点
                Element Enabled = (Element)Root.selectSingleNode("Enabled"); //获得是否启用memcached节点
                Element Servers = (Element)Root.selectSingleNode("Servers"); //获得可用的服务器列表父节点
                Element Config = (Element)Root.selectSingleNode("Config"); //获得运行环境参数列表父节点                
            }
        }catch(Exception e){
            System.out.println(e.toString());
        }

   dom4j
   dom4j
   1.6

转:Spring MVC getServletConfigClasses和getRootConfigClasses

在不使用Web.XML中配置搭建spring MVC框架时,一般需要创建一个类来继承AbstractAnnotationConfigDispatcherServletInitializer,如下代码所示:

public class SpittrWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class[] getRootConfigClasses() {
        return new Class[] { RootConfig.class };
    }
    @Override
    protected Class[] getServletConfigClasses() {
        return new Class[] { WebConfig.class };
    }
    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }
}

其中有两个方法,getRootConfigClasses()getServletConfigClasses()一直让我很疑惑,两个方法的说明分别是:

  • getRootConfigClasses: Specify @Configuration and/or @Component classes to be provided to the root application context.(将有@Component注解或者@Component注解的配置类提供给根应用上下文)
  • getServletConfigClasses:Specify @Configuration and/or @Component classes to be provided to the dispatcher servlet application context.(将有@Component注解或者@Component注解的配置类提供给根应用上下文)

两者之间有什么区别呢?后来在Spring的官方文档中找到答案。在Spring的官方文档中有这样一段话提到:

ApplicationContext instances in Spring can be scoped. In the Web MVC framework, each DispatcherServlet has its own WebApplicationContext, which inherits all the beans already defined in the root WebApplicationContext. The root WebApplicationContext should contain all the infrastructure beans that should be shared between your other contexts and Servlet instances. These inherited beans can be overridden in the servlet-specific scope, and you can define new scope-specific beans local to a given Servlet instance.

文档连接
粗略翻译一下:

在Spring中,应用上下文(ApplicationContext)的实例是可以范围化(Scoped)的,在Web MVC框架中,每个DispatcherServlet都可以有自己的Web应用上下文(WebApplicationContext),每个DispatcherServlet自己的WebApplicationContext继承所有的在根应用上下文中的bean。根应用上下文应该包含在其他DispatcherServlet中会用到的bean,比如DataSource等,这些在根应用上下文中的bean可以在DispatcherServlet自己的WebApplicationContext中被重载。

在Spring MVC中我们其实是可以创建出多个DispatcherServlet的(只要创建多个继承自AbstractAnnotationConfigDispatcherServletInitializer的类即可)。而每个DispatcherServlet有自己的应用上下文(WebApplicationContext),这个应用上下文只针对这个DispatcherServlet有用。这也就是getServletConfigClasses的作用,获取这个DispatcherServlet的应用上下文的配置类。

而除了每个DispatcherServlet配置类的应用上下文之外,还有一个根应用上下文,这个应用上下文的作用是为了在多个DispatcherServlet之间共享Bean,比如数据源Bean,这就是getRootConfigClasses的作用,用于返回根应用上下文的配置类。Spring框架的机制会保证如果在当前DispatcherServlet的应用上下文中没有找到想要的bean时,会去根应用上下文中去找。

上两张官方文档中的图:这两张图片也阐述了两种用法。

图片1

这是其中的一种用法,当应用中有DispatcherServlet时,每个DispatcherServlet的bean如Controller,ViewResolver,HandlerMapping等,均在getServletConfigClasses返回的类中配置而一些公共的bean,如Services,Repository均在getRootConfigClasses返回的类中配置

图片2

这是另外一种用法,但应用中只有一个DispatcherServlet中时,可以将所有的bean配置均写在根应用上下文中。DispatcherServlet获取想要的bean时,如果没有在自己的应用上下文中找到,则会自动到根应用上下文中去找。

这也就是Spring MVC的ApplicationContext继承机制。

java相关库

http://commons.apache.org/
commons库,包括了各种常用的库如:io,lang,codex等。
——————————————–
Apache Commons IO 包绝对是好东西,地址在http://commons.apache.org/proper/commons-io/,下面用例子分别介绍:
1) 工具类
2) 输入
3) 输出
4) filters过滤
5) Comparators
6) 文件监控

http://hc.apache.org/
HttpComponents库,主要包括了HttpClient的组件,包括异步和同步方式。

——————–
smart-framework,有助于了解一个框架的实现原理。
http://git.oschina.net/huangyong/smart-framework
http://git.oschina.net/huangyong/smart-sample

Servlet创建的三种方式

源代码路径:https://git.oschina.net/kxtry/servletwaycreate
以下是基于servlet3.0API而创建的。
0.pom.xml的准备


        
            javax.servlet
            javax.servlet-api
            3.0.1
        
    

1.ServletContainerInitializer的方式。

在resources/META-INF/services/javax.servlet.ServletContainerInitializer文件中增加以下内容。
HandlerInitializer,如果是有包名,则需要添加上包名如hello.HandlerInitializer
public class ServletManualReg extends HttpServlet {
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().print("ServletManualReg.hello");
    }
}
import javax.servlet.ServletContainerInitializer;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;
import javax.servlet.ServletRegistration;
import javax.servlet.annotation.HandlesTypes;
import java.util.Set;

@HandlesTypes({HandlerInitializer.class})
public class HandlerInitializer implements ServletContainerInitializer {
    public void onStartup(Set> c, ServletContext servletContext)
            throws ServletException {
        System.out.println("onStartup");
        ServletRegistration registration = servletContext.addServlet("ServletManualReg", "hello.ServletManualReg");
        registration.addMapping("/manual_reg");
        System.out.println("leaving onStartup");
    }
}

2.使用ServletContextListener注册

import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

public class DynRegServlet extends HttpServlet {
    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        response.getWriter().print("DynRegServlet.hello");
    }
}
import javax.servlet.*;
import javax.servlet.annotation.WebListener;

@WebListener
public class DynRegListener implements ServletContextListener {

    public void contextDestroyed(ServletContextEvent arg0) {
    }

    public void contextInitialized(ServletContextEvent sce) {
        ServletContext servletContext = sce.getServletContext() ;
        Servlet dynRegServlet = null ;
        try {
            dynRegServlet = servletContext.createServlet(DynRegServlet.class) ;
        } catch (ServletException e) {
            e.printStackTrace();
        }
        ServletRegistration.Dynamic dynamic = servletContext.addServlet("DynRegServlet", dynRegServlet) ;
        dynamic.addMapping("/dynamic_reg") ;
    }
}

3.使用WebServlet注解注册


import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * 使用@WebServlet实现了,自动注册。
 */
@WebServlet(name = "ServletNotationReg", urlPatterns = "/notation_reg")
public class ServletNotationReg extends HttpServlet {
    public ServletNotationReg(){
        int i = 0;
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.getWriter().print("ServletNotationReg.hello");
    }
}

BeanNameUrlHandlerMapping遍历Controller注解过程

1.关键运行栈细节

2.关注AbstractDetectingUrlHandlerMapping类的detectHandlers函数。

protected void detectHandlers() throws BeansException {
        if(this.logger.isDebugEnabled()) {
            this.logger.debug("Looking for URL mappings in application context: " + this.getApplicationContext());
        }
        /*获取所有bean的名字,然后遍历测试*/
        String[] beanNames = this.detectHandlersInAncestorContexts?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.getApplicationContext(), Object.class):this.getApplicationContext().getBeanNamesForType(Object.class);
        String[] var2 = beanNames;
        int var3 = beanNames.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String beanName = var2[var4];
            /*将检验beanName的名字,当名字是以反斜扛开头的,均当作是一个URL处理器*/
            String[] urls = this.determineUrlsForHandler(beanName);
            if(!ObjectUtils.isEmpty(urls)) {
                this.registerHandler(urls, beanName);
            } else if(this.logger.isDebugEnabled()) {
                this.logger.debug("Rejected bean name \'" + beanName + "\': no URL paths identified");
            }
        }
    }

3.上图局部变量截图

4.附上determineUrlsForHandler的相关代码。

protected String[] determineUrlsForHandler(String beanName) {
        ArrayList urls = new ArrayList();
        if(beanName.startsWith("/")) {
            urls.add(beanName);
        }

        String[] aliases = this.getApplicationContext().getAliases(beanName);
        String[] var4 = aliases;
        int var5 = aliases.length;

        for(int var6 = 0; var6 < var5; ++var6) {
            String alias = var4[var6];
            if(alias.startsWith("/")) {
                urls.add(alias);
            }
        }

        return StringUtils.toStringArray(urls);
    }

5.附相关代码

@Controller("/demo_servlet2")
public class Demo2Servlet extends HttpServlet {	
	@PostConstruct  //init-method="init"
	@Override
	public void init() throws ServletException {
		// TODO Auto-generated method stub
		logger.info("Demo2Servlet init start");		
		
		logger.info("Demo2Servlet init end");
	}

	@RequestMapping("/findall")
	public String handleList(Model model) {
		logger.info("demo02  handleList");
		return "demo";
	}

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub

		logger.info("Demo2Servlet service start");

		response.setContentType(CONTENT_TYPE);
		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		String result = demoService.getById(1l).getName();
		//Integer.valueOf(result); //测试异常显示页面
		PrintWriter out = response.getWriter();
		out.println("");
		out.println("\n");
		out.println("" + result + "\n");
		out.println("\n");

		out.flush();
		out.close();

		logger.info("Demo2Servlet service end");
	}

	@PreDestroy //destroy-method="destroy"
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		logger.info("Demo2Servlet destroy start");
		
		logger.info("Demo2Servlet destroy end");
	}
	
}

BeanNameUrlHandlerMapping与RequestMappingHandlerMapping的区别

1.前者只依赖@Controller(“/abc”)注解进行识别,后者是依赖Controller和ReqestMapping注解进行识别。
2.前者的类对象是由Servlet接口派生,后者是无派生关系的普通类。

@Controller
@RequestMapping("/demo")
public class DemoController {

	@RequestMapping("/findall")
	public String handleList(Model model) {
		logger.info("demo02  handleList");
		List list = demoService.findAll();
		model.addAttribute("results", list);
		return "demo";
	}
}

@Controller("/demo_servlet2")
public class Demo2Servlet extends HttpServlet {	
	@PostConstruct  //init-method="init"
	@Override
	public void init() throws ServletException {
		// TODO Auto-generated method stub
		logger.info("Demo2Servlet init start");		
		
		logger.info("Demo2Servlet init end");
	}

	@RequestMapping("/findall")
	public String handleList(Model model) {
		logger.info("demo02  handleList");
		return "demo";
	}

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub

		logger.info("Demo2Servlet service start");

		response.setContentType(CONTENT_TYPE);
		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		String result = demoService.getById(1l).getName();
		//Integer.valueOf(result); //测试异常显示页面
		PrintWriter out = response.getWriter();
		out.println("");
		out.println("\n");
		out.println("" + result + "\n");
		out.println("\n");

		out.flush();
		out.close();

		logger.info("Demo2Servlet service end");
	}

	@PreDestroy //destroy-method="destroy"
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		logger.info("Demo2Servlet destroy start");
		
		logger.info("Demo2Servlet destroy end");
	}
	
}

RequestMappingHandlerMapping遍历Controller和RequestMapping注解过程


在AbstractHandlerMethodMapping类中,获取HandlerMethods。

public void afterPropertiesSet() {
        this.initHandlerMethods();
    }

    protected void initHandlerMethods() {
        if(this.logger.isDebugEnabled()) {
            this.logger.debug("Looking for request mappings in application context: " + this.getApplicationContext());
        }
        /*获取所有bean形成列表,后续将会遍历这些bean*/
        String[] beanNames = this.detectHandlerMethodsInAncestorContexts?BeanFactoryUtils.beanNamesForTypeIncludingAncestors(this.getApplicationContext(), Object.class):this.getApplicationContext().getBeanNamesForType(Object.class);
        String[] var2 = beanNames;
        int var3 = beanNames.length;

        for(int var4 = 0; var4 < var3; ++var4) {
            String beanName = var2[var4];
            /*通过isHandler函数,检查是否是Controller和RequestMapping注解。它是通过AnnotationUtils和ClassUtils静态类遍历的*/
            if(!beanName.startsWith("scopedTarget.") && this.isHandler(this.getApplicationContext().getType(beanName))) {
                this.detectHandlerMethods(beanName);
            }
        }
        /*获取所有requestMapping对象完成注册的最后一步。*/
        this.handlerMethodsInitialized(this.getHandlerMethods());
    }

在该函数中检查局部变量

在AbstractHandlerMethodMapping的派生类中,即RequestMappingHandlerMapping中,实现了isHandler的类型判断。

在getHandlerMethods中

public Map getHandlerMethods() {
        return Collections.unmodifiableMap(this.handlerMethods);
    }


此外,附加findall代码。

@Controller
@RequestMapping("/demo")
public class DemoController {

	@RequestMapping("/findall")
	public String handleList(Model model) {
		logger.info("demo02  handleList");
		List list = demoService.findAll();
		model.addAttribute("results", list);
		return "demo";
	}
}



@Controller("/demo_servlet2")
public class Demo2Servlet extends HttpServlet {	
	@PostConstruct  //init-method="init"
	@Override
	public void init() throws ServletException {
		// TODO Auto-generated method stub
		logger.info("Demo2Servlet init start");		
		
		logger.info("Demo2Servlet init end");
	}

	@RequestMapping("/findall")
	public String handleList(Model model) {
		logger.info("demo02  handleList");
		return "demo";
	}

	@Override
	protected void service(HttpServletRequest req, HttpServletResponse response)
			throws ServletException, IOException {
		// TODO Auto-generated method stub

		logger.info("Demo2Servlet service start");

		response.setContentType(CONTENT_TYPE);
		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		String result = demoService.getById(1l).getName();
		//Integer.valueOf(result); //测试异常显示页面
		PrintWriter out = response.getWriter();
		out.println("");
		out.println("\n");
		out.println("" + result + "\n");
		out.println("\n");

		out.flush();
		out.close();

		logger.info("Demo2Servlet service end");
	}

	@PreDestroy //destroy-method="destroy"
	@Override
	public void destroy() {
		// TODO Auto-generated method stub
		logger.info("Demo2Servlet destroy start");
		
		logger.info("Demo2Servlet destroy end");
	}
	
}

DispatcherServlet中的URL处理

1.当处理一个URL请求时,将会在DispatcherServlet模块中,循环获取相应的处理Handler。如下图:

2.getHandler的关键函数

protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        Iterator var2 = this.handlerMappings.iterator();

        HandlerExecutionChain handler;
        do {
            if(!var2.hasNext()) {
                return null;
            }

            HandlerMapping hm = (HandlerMapping)var2.next();
            if(this.logger.isTraceEnabled()) {
                this.logger.trace("Testing handler map [" + hm + "] in DispatcherServlet with name \'" + this.getServletName() + "\'");
            }
            //通过遍历比较,
            handler = hm.getHandler(request);
        } while(handler == null);

        return handler;
    }

3.getHandler中的局部变量






spring注册RestController的关键过程

1.注册RestController时,进入它的反射过程栈信息。

2.registerHandlerMethod时的其中一个变量信息。

3.registerHandlerMethod的具体函数代码

protected void registerHandlerMethod(Object handler, Method method, T mapping) {
        HandlerMethod newHandlerMethod = this.createHandlerMethod(handler, method);
        HandlerMethod oldHandlerMethod = (HandlerMethod)this.handlerMethods.get(mapping);
        if(oldHandlerMethod != null && !oldHandlerMethod.equals(newHandlerMethod)) {
            throw new IllegalStateException("Ambiguous mapping found. Cannot map \'" + newHandlerMethod.getBean() + "\' bean method \n" + newHandlerMethod + "\nto " + mapping + ": There is already \'" + oldHandlerMethod.getBean() + "\' bean method\n" + oldHandlerMethod + " mapped.");
        } else {
            this.handlerMethods.put(mapping, newHandlerMethod);
            if(this.logger.isInfoEnabled()) {
                this.logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
            }

            Set patterns = this.getMappingPathPatterns(mapping);
            Iterator var7 = patterns.iterator();

            while(var7.hasNext()) {
                String pattern = (String)var7.next();
                if(!this.getPathMatcher().isPattern(pattern)) {
                    this.urlMap.add(pattern, mapping);
                }
            }

        }
    }

3.preInstantiateSingletons的函数是枚举当前的注解定义,把所有注解定义列出来,并进行逐一获取所有注解相关的配置。

public void preInstantiateSingletons() throws BeansException {
        if(this.logger.isDebugEnabled()) {
            this.logger.debug("Pre-instantiating singletons in " + this);
        }

        Map var2 = this.beanDefinitionMap;
        ArrayList beanNames;
        synchronized(this.beanDefinitionMap) {
            beanNames = new ArrayList(this.beanDefinitionNames);
        }

        Iterator var8 = beanNames.iterator();

        while(true) {
            while(true) {
                String beanName;
                RootBeanDefinition bd;
                do {
                    do {
                        do {
                            if(!var8.hasNext()) {
                                return;
                            }

                            beanName = (String)var8.next();
                            bd = this.getMergedLocalBeanDefinition(beanName);
                        } while(bd.isAbstract());
                    } while(!bd.isSingleton());
                } while(bd.isLazyInit());

                if(this.isFactoryBean(beanName)) {
                    final FactoryBean factory = (FactoryBean)this.getBean("&" + beanName);
                    boolean isEagerInit;
                    if(System.getSecurityManager() != null && factory instanceof SmartFactoryBean) {
                        isEagerInit = ((Boolean)AccessController.doPrivileged(new PrivilegedAction() {
                            public Boolean run() {
                                return Boolean.valueOf(((SmartFactoryBean)factory).isEagerInit());
                            }
                        }, this.getAccessControlContext())).booleanValue();
                    } else {
                        isEagerInit = factory instanceof SmartFactoryBean && ((SmartFactoryBean)factory).isEagerInit();
                    }

                    if(isEagerInit) {
                        this.getBean(beanName);
                    }
                } else {
                    this.getBean(beanName);
                }
            }
        }
    }

spring4.x之HttpMessageConverter

public class WebMvcConfigurationSupport implements ApplicationContextAware, ServletContextAware {
    private static boolean romePresent = ClassUtils.isPresent("com.rometools.rome.feed.WireFeed", WebMvcConfigurationSupport.class.getClassLoader());
    private static final boolean jaxb2Present = ClassUtils.isPresent("javax.xml.bind.Binder", WebMvcConfigurationSupport.class.getClassLoader());
    private static final boolean jackson2Present = ClassUtils.isPresent("com.fasterxml.jackson.databind.ObjectMapper", WebMvcConfigurationSupport.class.getClassLoader()) && ClassUtils.isPresent("com.fasterxml.jackson.core.JsonGenerator", WebMvcConfigurationSupport.class.getClassLoader());
    private static final boolean jackson2XmlPresent = ClassUtils.isPresent("com.fasterxml.jackson.dataformat.xml.XmlMapper", WebMvcConfigurationSupport.class.getClassLoader());
    private static final boolean gsonPresent = ClassUtils.isPresent("com.google.gson.Gson", WebMvcConfigurationSupport.class.getClassLoader());

spring内部已经内置了,feed,json,protobuf的支持,只要在pom.xml的配置文件中添加相应的库支持,即可。



   com.fasterxml.jackson.core
   jackson-core
   ${jackson.version}


   com.fasterxml.jackson.core
   jackson-databind
   ${jackson.version}



 com.google.protobuf
 protobuf-java
 2.5.0


 com.googlecode.protobuf-java-format
 protobuf-java-format
 1.2