精华内容
下载资源
问答
  • 若果写多个的话,会存在初始化时出现优先级不同,如果有相互依赖关系就会出现问题 解决方法: 1,@DependOn 注解(当一个 bean 需要在另一个 bean 初始化之后再初始化时,可以使用这个注解) 2,将逻辑都写到一个...
    // 实现InitializingBean接口  重写此方法(初始化完bean就执行此方法)   
    @Override
    public void afterPropertiesSet()

    一个项目中尽量只写一个InitializingBean接口 。

    若果写多个的话,会存在初始化时出现优先级不同,如果有相互依赖关系就会出现问题

    解决方法:

    1,@DependOn 注解(当一个 bean 需要在另一个 bean 初始化之后再初始化时,可以使用这个注解)

    2,将逻辑都写到一个InitializingBean里

    展开全文
  • 一个接口通常用来定义实例方法的声明,而方法的实现则有继承类来完成. 如果继承类在实例时需要外界传递参数,这时候对于匿名类来说,简直是梦魇. 因为匿名类的构造方式只能是默认的构造方法,不接收任何参数. ...
    一个接口通常用来定义实例方法的声明,而方法的实现则有继承类来完成.

    如果继承类在实例化时需要外界传递参数,这时候对于匿名类来说,简直是梦魇.

    因为匿名类的构造方式只能是默认的构造方法,不接收任何参数.

    通常的解决办法是使用final关键字声明参数,然后在内部使用.

    这种方式有三个缺点
    1,参数一旦被声明为final对象,就不能再改变.
    2,如果参数之前没有被声明为final类型,则必须重新声明一个final参数,然后用之前的参数进行赋值.
    3,这种传递方式过于丑陋,不过优雅

    鉴于以上情况,在实际编码过程中,作者采用了一种比较优雅的方法来初始化匿名接口实例.

    代码示例如下:
    //定义一个Student接口,该接口有一个方法显示自己的名称
    interface Student {
    void showName();
    }
    public class Test {

    //该方法用指定的名称创建一个Student对象实例
    private static Student newStudent(String name) {
    return new Student() {
    private String name;

    public void showName() {
    System.out.println(name);
    }

    private Student init(String name) {
    this.name = name;
    return this;
    }
    }.init(name);
    }

    public static void main(String[] args) {
    newStudent("LoveKitty").showName();
    }
    }
    展开全文
  •  Spring MVC框架中使用HandlerMapping来进行请求到处理器的映射处理... 而回到这个问题,一般要思考两个问题: 1、框架如何初始化HandlerMapping接口. 2、 框架如何使用HandlerMapping接口进行请求到处理器的...
          Spring MVC框架中使用HandlerMapping来进行请求到处理器的映射处理。
         那么就会有一个问题:那么框架到底是如何从Url获取到一个处理器的呢? 
         而回到这个问题,一般要思考两个问题:
         1、框架如何初始化HandlerMapping接口.
                      2、 框架如何使用HandlerMapping接口进行请求到处理器的映射处理。
        现在,先来看看第一个问题。我们以@RequestMapping为例,是如何处理的。
         其中SpringMVC容器提供了RequestMappingHandlerMapping实现类来处理这个注解.
      debug源码,发现是在初始化容器的时候会注册RequestMappingHandlerMappingBean:
       
        步骤如下:

        1:在初始化容器的时候,有一个步骤: 

          AbstractAutowireCapableBeanFactory.initializeBeaninvoke
         在这方法中有一个invokeInitMethods, 在这个代码中会执行bean.afterPropertiesSet()方法
        
         2:afterPropertiesSet()方法
         该方法是InitializingBean的一个接口,所有实现了这个接口,都要实现  afterPropertiesSet()方法。
         在初始化bean的时候调用。
         AbstractHandlerMethodMapping.afterPropertiesSet()
         AbstractHandlerMethodMapping实现了这个接口,也就是实现了afterPropertiesSet()方法,
        在初始化bean的时候会调用 AbstractHandlerMethodMapping.afterPropertiesSet()
       
        3: initHandlerMethods()
       在afterPropertiesSet()方法中调用了initHandlerMethods()方法.
       这个方法用来从所有的bean中检测出符合规则的类和方法,
       然后生成一个调用RequestMappingHandlerMapping.getMappingForMethod() 产生一个 RequestMappingInfo对象,
       在registerHandlerMethod注册过程中:根据RequestMappingInfo对象生成一个HandlerMethod对象。
     
       4: 注册到AbstractHandlerMethodMapping的handlerMethods和urlMap中.
         这个是变量的声明
         Map<T, HandlerMethod> handlerMethods;
        MultiValueMap<String, T> urlMap;
       会把相关的对象保存到上面的Map中.
        涉及到的相关类:
         InitializingBean、AbstractHandlerMethodMapping、RequestMappingHandlerMapping、R equestMappingInfo、HandlerMethod.
      
       代码分析。。。:
      
       一: AbstractHandlerMethodMapping.initHandlerMethods()
       这个方法用来扫描容器的bean,监测出所以的映射方法(Handler Methods),并且注册到映射处理器中(HandlerMapping)。
       
    /**  
      * Scan beans in the ApplicationContext, detect and register handler methods.
      * @see #isHandler(Class)
      * @see #getMappingForMethod(Method, Class)
      * @see #handlerMethodsInitialized(Map)
      */
     protected void initHandlerMethods() {
      if (logger.isDebugEnabled()) {
       logger.debug("Looking for request mappings in application context: " + getApplicationContext());
      }
       String[] beanNames = (this.detectHandlerMethodsInAncestorContexts ?
        BeanFactoryUtils.beanNamesForTypeIncludingAncestors(getApplicationContext(), Object.class) :
        getApplicationContext().getBeanNamesForType(Object.class));
    
      for (String beanName : beanNames) {
       if (isHandler(getApplicationContext().getType(beanName))){
        detectHandlerMethods(beanName);
       }
      }
      handlerMethodsInitialized(getHandlerMethods());
     }
       这个方法步骤如下:
       1 :从容器中获得所有bean的名字
       2:遍历容器中的bean,判断Bean是否属于Handler,如果是则检测出所以的HandlerMethod方法并且注册到容器中.
       3:handlerMethodsInitialized这个方法里的方法体为空,没有做任何的处理
    注意:在上面的代码中,isHandler()方法是个抽象方法,由子类来提供具体的实现。
    比如 RequestMappingHandlerMapping提供了实现,代码如下:
    	@Override
    	protected boolean isHandler(Class<?> beanType) {
    		return ((AnnotationUtils.findAnnotation(beanType, Controller.class) != null) ||
    				(AnnotationUtils.findAnnotation(beanType, RequestMapping.class) != null));
    	}
    
     在这里来判断当前的bean是否有Controller或者RequestMapping注解。
    再来看下detectHandlerMethods的代码
    	protected void detectHandlerMethods(final Object handler) {
    		Class<?> handlerType =
    				(handler instanceof String ? getApplicationContext().getType((String) handler) : handler.getClass());
    
    		// Avoid repeated calls to getMappingForMethod which would rebuild RequestMatchingInfo instances
    		final Map<Method, T> mappings = new IdentityHashMap<Method, T>();
    		final Class<?> userType = ClassUtils.getUserClass(handlerType);
    
    		Set<Method> methods = HandlerMethodSelector.selectMethods(userType, new MethodFilter() {
    			public boolean matches(Method method) {
    				T mapping = getMappingForMethod(method, userType);
    				if (mapping != null) {
    					mappings.put(method, mapping);
    					return true;
    				}
    				else {
    					return false;
    				}
    			}
    		});
    
    		for (Method method : methods) {
    			registerHandlerMethod(handler, method, mappings.get(method));
    		}
    	}
     
      大概步骤如下:
    1 : 通过HandlerMethodSelector.selectMethods()方法来从当前的处理器中匹配出具有映射处理的方法。
    2:取出映射的方法后,则调用registerHandlerMethod()注册到处理器中。
    注意:
    在上面代码中,getMappingForMethod(method, userType)是个抽象方法,具体由子类来实现。
    比如RequestMappingHandlerMapping中提供了如下的实现:
    	@Override
    	protected RequestMappingInfo getMappingForMethod(Method method, Class<?> handlerType) {
    		RequestMappingInfo info = null;
    		RequestMapping methodAnnotation = AnnotationUtils.findAnnotation(method, RequestMapping.class);
    		if (methodAnnotation != null) {
    			RequestCondition<?> methodCondition = getCustomMethodCondition(method);
    			info = createRequestMappingInfo(methodAnnotation, methodCondition);
    			RequestMapping typeAnnotation = AnnotationUtils.findAnnotation(handlerType, RequestMapping.class);
    			if (typeAnnotation != null) {
    				RequestCondition<?> typeCondition = getCustomTypeCondition(handlerType);
    				info = createRequestMappingInfo(typeAnnotation, typeCondition).combine(info);
    			}
    		}
    		return info;
    	}
     具体步骤:
    1:从当前类中取出RequestMapping 注解。
    2:如果注解不为空的话,则进行一系列处理,生成一个RequestMappingInfo对象。

     再来看看registerHandlerMethod这个方法的实现,看看是是把HandlerMethod注册到哪里的?

    代码:

     

    /**
    	 * Register a handler method and its unique mapping.
    	 * @param handler the bean name of the handler or the handler instance
    	 * @param method the method to register
    	 * @param mapping the mapping conditions associated with the handler method
    	 * @throws IllegalStateException if another method was already registered
    	 * under the same mapping
    	 */
    	protected void registerHandlerMethod(Object handler, Method method, T mapping) {
    		HandlerMethod newHandlerMethod = createHandlerMethod(handler, method);
    		HandlerMethod oldHandlerMethod = 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.");
    		}
    
    		this.handlerMethods.put(mapping, newHandlerMethod);
    		if (logger.isInfoEnabled()) {
    			logger.info("Mapped \"" + mapping + "\" onto " + newHandlerMethod);
    		}
    
    		Set<String> patterns = getMappingPathPatterns(mapping);
    		for (String pattern : patterns) {
    			if (!getPathMatcher().isPattern(pattern)) {
    				this.urlMap.add(pattern, mapping);
    			}
    		}
    	}
    从上面代码可以看出是 注册到下面两个变量中。
          
      private final Map<T, HandlerMethod> handlerMethods = new LinkedHashMap<T, HandlerMethod>();
       private final MultiValueMap<String, T> urlMap = new LinkedMultiValueMap<String, T>();
     
    一看定义就知道, urlMap 的key是个String类型,表示的是请求url,而T应该是RequestMappingInfo.
    handlerMethods 的key是RequestMappingInfo。
    也就是请求的时候,会先根据请求url从urlMap中查找对应的RequestMappingInfoBean,
    然后再从handlerMethods 方法中找到对应的HandlerMethod方法,这个HandlerMethod就是实际的业务处理逻辑。
    总结:
    这篇文章分析SpringMVC容器在初始化的时候,是如何初始化映射处理器的。
    1:容器初始化的时候是在哪个入口 进入 初始化映射处理器的。
    2: 初始化映射处理器的流程是如何检测出所有符合规则的 Handler类和HandlerMethod方法,并且是如何注册到容器中。
     在这个整个流程中涉及到了InitializingBean、RequestMappingHandlerMapping、RequestMappingHandlerMapping、RequestMappingInfo、HandlerMethod.等类.

     

     

    展开全文
  • windows窗口初始化问题

    2015-10-13 07:12:20
    windows API 中是否有类似与windowinit的窗口初始化接口,该接口可以返回窗口句柄。
  • ServletConfig 是一个接口,它怎样传递给他一格对象来进行初始化呢?其实,是这个对象是由 servlet 容 器来实例化的,由容器产生一格 ServletConfig 的实现类的对象,然后传递给 Servlet ②我们有些
    一、Servlet初始化

    ①Servlet在初始化的时候,是通过init(ServletConfig config) 或 init() 来执行的。
    ServletConfig 是一个接口,它怎样传递给他一格对象来进行初始化呢?其实,是这个对象是由 servlet 容
    器来实例化的,由容器产生一格 ServletConfig 的实现类的对象,然后传递给 Servlet

    ②我们有些时候可能在 Servlet 初始化时给它一些固定的配置参数,那么这些参数是怎样传递到 Servlet
    呢?其实,我们在 web.xml 中给 servlet 配置启动参数,在容器对 servlet 进行初始化的时候,会收集你所配置的参数,记录在 ServletConfig 的实现类中,所以你才可以通过 ServletConfig 对象的
    public String getInitParameter(String name); 或
    public Enumeration getInitParameterNames();
    方法来取得你已经配置好的参数,也就是说,你对servlet的配置都已经记录在ServletConfig对象中了。
    结论:你对Servlet的配置,在Servlet的初始化时都由容器来收集并且记录到ServletConfig的实现类中。

    ③我们来看一个 Servlet 的配置
    <servlet>
    <servlet-name>index</servlet-name>
    <servlet-class>org.zy.pro.sw.servlet.IndexServlet</servlet-class>
    <init-param>
    <param-name>dbconfig</param-name>
    <param-value>/WEB-INF/dbconfig.xml</param-value>
    </init-param>
    </servlet>
    在此,我们实现对数据库的配置文件的加载。
    当 Servlet 初始化完成后,我们可以通过
    String dbconf=this.getServletConfig().getInitParameter("dbconfig")
    来取得我们的配置的参数的值。
    但是,我们仅能得到一个配置的字符串。之后我们可以通过配置文件取得我们的数据库的配置参数,然后

    对数据库进行初始化。
    其实我们也可以通过传递一个类的名字串,然后再实例化。
    <init-param>
    <param-name>dbconfig</param-name>
    <param-value>org.zy.util.db.DBUtil</param-value>
    </init-param>
    我们先取得配置参数:
    String dbconf=this.getServletConfig().getInitParameter("dbconfig") ;
    然后通过
    Class.forName(dbconf).getInstance();
    来实例化对象,就可以实现对数据库的调用了。
    结论:在 web.xml 中对 Servlet 的初始化,只能传递字符串类型的数据
    ④  ServletContext
    ServletContext 是负责和 Servlet 的上文和下文交互,上面和 Servlet 容器交互,下面和 Servlet 中的请求
    和相应进行交互。 在 ServletConfig 中,public ServletContext getServletContext(); 方法实现取得当前 ServletContext 的对象。 你可能要问, ServletContext 是一个接口,那么你如何取得他的对象呢?
    其实这个问题和 ServletConfig 相同,都是在 Servlet 进行初始化的时候产生的对象,是由容器来初始化的。



    转自:http://blog.163.com/ly_qmoa/blog/static/263360542008112081839777/
    二、ServletContext详解
    ServletContext,是一个全局的储存信息的空间,服务器启动之后,其就存在,服务器关闭,其才释放。request,一个用户可有多个;session,一个用户一个;而servletContext,所有用户共用一个。所以,为了节省空间,提高效率,ServletContext中,要放必须的、重要的、所有用户需要共享的线程又是安全的一些信息。

    换一种方式说吧,运行在JAVA虚拟机中的每一个Web应用程序都有一个与之相关的Servlet上下文。ServletContext对象是Web服务器中的一个已知路径的根,Servlet上下文被定位于http://localhost:8080/项目名.以 /项目名 请求路径(称为上下文路径)开始的所有请求被发送到与此ServletContext关联的Web应用程序。一个ServletContext对象表示了一个Web应用程序的上下文。

    Servlet上下文:Servlet上下文提供对应用程序中所有Servlet所共有的各种资源和功能的访问。Servlet上下文API用于设置应用程序中所有Servlet共有的信息。Servlet可能需要共享他们之间的共有信息。运行于同一服务器的Servlet有时会共享资源,如JSP页面、文件和其他Servlet。

    举例:

    如,做一个购物类的网站,要从数据库中提取物品信息,如果用session保存这些物品信息,每个用户都访问一便数据库,效率就太低了;所以要用来Servlet上下文来保存,在服务器开始时,就访问数据库,将物品信息存入Servlet上下文中,这样,每个用户只用从上下文中读入物品信息就行了。

    3.1 ServletContext接口简介

    ServletContext接口定义了运行servlet的web应用的servlet视图。容器供应商负责提供servlet容器内ServletContext接口的实现。使用ServletContext对象,servlet可以记录事件日志,获取资源的URL地址,并且设置和保存上下文内可以访问的其他servlet的属性。

    ServletContext以web的已知路径为根路径。比如,假定一个servlet上下文位于http://www.mycorp.com/catalog。以/catalog请求路径开头的所有请求,已知为上下文路径,被路由到和该ServletContext关联的web应用。

    3.2 ServletContext接口作用域

    容器中部署的每一个web应用都有一个ServletContext接口的实例对象与之关联。如果容器被分布在多个虚拟机上,一个web应用将在每一个VM中有一个ServletContext实例。

    不作为web应用一部分部署的容器中的servlet默认是“默认”web应用的一部分,有一个默认的ServletContext。在分布式容器中。默认ServletContext是非分布式的,并且必须只存在于一个VM中。

    3.3 初始化参数

    ServletContext接口的初始化参数允许servlet访问与web应用相关的上下文初始化参数,这些由应用开发人员在部署描述符中指定:

    getInitParameter

    getInitParameterNames

    应用开发人员利用初始化参数传送配置信息。典型的例子是web管理员的e-mail地址或者一个持有关键数据的系统名称。

    3.4 上下文属性

    servlet可以通过名称将对象属性绑定到上下文。任何绑定到上下文的属性可以被同一个web应用的其他servlet使用。ServletContext接口的下列方法允许访问这种功能:

    setAttribute

    getAttribute

    getAttributeNames

    removeAttribute

    3.4.1 分布式容器中的上下文属性

    上下文属性对于创建它们的VM来说是本地的。这防止ServletContext属性存储于分布式容器的共享内存中。当信息需要在运行于分布式环境中的servlet之间共享时,信息被放入会话中,存储于数据库中,或者存储于EJB组件中。

    3.5 资源

    ServletContext接口通过下列方法提供对web应用组成的静态内容文档层级的直接访问,包括HTML,GIF和JPEG文件:

    getResource

    getResourceAsStream

    getResource和getResourceAsStream方法以“/”开头的字符串为参数,它指定上下文根路径的资源相对路径。文档的层级可能存在于服务器的文件系统,war文件,远程服务器或者在一些其它位置中。

    这些方法不用来获取动态内容。比如,在一个支持JSP规范1的容器中,getResource("/index.jsp")这种形式的方法调用将返回JSP源代码,而不是处理后的输出。
    Web应用资源的完整列表可以使用getResourcePaths(String path)方法访问。该方法语义的完整信息可以在本规范的API文档中找到。

    3.6 多个主机和ServletContext

    Web服务器可能支持一个服务器上多个逻辑主机共享一个IP地址。这功能有时被称为“虚拟主机”。这种情况下,每一个逻辑主机必须有它自己的servlet上下文或者servlet上下文组。Servlet上下文不可以被多个虚拟主机共享。

    3.7 重载考虑

    尽管容器供应商因为对于易于开发而实现的类加载不做要求,但是任何那样的实现必须确保所有它们可能使用2的所有servlet和类,被加载在单个类加载器作用域内。必须保证应用应该如开发人员预想的那样运转。作为开发辅助,绑定监听器的会话通知的完整语义应当由容器支持,在类加载上会话终止的监听上使用。

    上一代的容器创建新的类加载器以加载servlet,这和用来加载servlet上下文中使用的其他servlet或者类的类加载器不同。这可能造成servlet上下文内的对象引用指向一个意想不到的类或对象,造成意想不到的行为。需要阻止由新一代类加载器所引发的问题。

    3.7.1 临时工作目录

    每一个servlet上下文都需要一个临时存储目录。Servlet容器必须为每一个servlet上下文提供一个私有的临时目录,并且使它可以通过javax.servlet.context.tempdir上下文属性可用。这些属性关联的对象必须是java.io.File类型。

    这项需求认可了很多servlet引擎实现中提供的常见便利。容器不需要在servlet重启时维持临时目录的内容,但是需要确保一个servlet上下文的临时目录的内容对于该servlet容器上运行的其他web应用的servlet上下文不可见。

    三、Spring的Ioc容器初始化

    典型的web环境中,Spring IOC容器是怎样被载入和起作用的。
    简单的说,在web容器中,通过ServletContext为Spring的IOC容器提供宿主环境,对应的建立起一个IOC容器的体系。其中,首先需要建立的是根上下文,这个上下文持有的对象可以有业务对象,数据存取对象,资源,事物管理器等各种中间层对象。在这个上下文的基础上,和web MVC相关还会有一个上下文来保存控制器之类的MVC对象,这样就构成了一个层次化的上下文结构。在web容器中启动Spring应用程序就是一个建立这个上下文体系的过程。Spring为web应用提供了上下文的扩展接口
    WebApplicationContext:
    Java代码
    public interface WebApplicationContext extends ApplicationContext {  
    //这里定义的常量用于在ServletContext中存取根上下文  
    String ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE = WebApplicationContext.class.getName() + ".ROOT";  
    ......  
    //对WebApplicationContext来说,需要得到Web容器的ServletContext  
    ServletContext getServletContext();  


    而一般的启动过程,Spring会使用一个默认的实现,XmlWebApplicationContext - 这个上下文实现作为在web容器中的根上下文容器被建立起来,具体的建立过程在下面我们会详细分析。
    Java代码
    public class XmlWebApplicationContext extends AbstractRefreshableWebApplicationContext {  

    /** 这是和web部署相关的位置信息,用来作为默认的根上下文bean定义信息的存放位置*/ 
    public static final String DEFAULT_CONFIG_LOCATION = "/WEB-INF/applicationContext.xml";  
    public static final String DEFAULT_CONFIG_LOCATION_PREFIX = "/WEB-INF/";  
    public static final String DEFAULT_CONFIG_LOCATION_SUFFIX = ".xml";  

    //我们又看到了熟悉的loadBeanDefinition,就像我们前面对IOC容器的分析中一样,这个加载工程在容器的refresh()的时候启动。  
    protected void loadBeanDefinitions(DefaultListableBeanFactory beanFactory) throws IOException {  
    //对于XmlWebApplicationContext,当然使用的是XmlBeanDefinitionReader来对bean定义信息来进行解析  
    XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);  

    beanDefinitionReader.setResourceLoader(this);  
    beanDefinitionReader.setEntityResolver(new ResourceEntityResolver(this));  

    initBeanDefinitionReader(beanDefinitionReader);  
    loadBeanDefinitions(beanDefinitionReader);  
    }  

    protected void initBeanDefinitionReader(XmlBeanDefinitionReader beanDefinitionReader) {  
    }  
    //使用XmlBeanDefinitionReader来读入bean定义信息  
    protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException {  
    String[] configLocations = getConfigLocations();  
    if (configLocations != null) {  
    for (int i = 0; i < configLocations.length; i++) {  
    reader.loadBeanDefinitions(configLocations[i]);  
    }  
    }  
    }  
    //这里取得bean定义信息位置,默认的地方是/WEB-INF/applicationContext.xml  
    protected String[] getDefaultConfigLocations() {  
    if (getNamespace() != null) {  
    return new String[] {DEFAULT_CONFIG_LOCATION_PREFIX + getNamespace() + DEFAULT_CONFIG_LOCATION_SUFFIX};  
    }  
    else {  
    return new String[] {DEFAULT_CONFIG_LOCATION};  
    }  
    }  


    对于一个Spring激活的web应用程序,可以通过使用Spring代码声明式的指定在web应用程序启动时载入应用程序上下文(WebApplicationContext),Spring的ContextLoader是提供这样性能的类,我们可以使用 ContextLoaderServlet或者ContextLoaderListener的启动时载入的Servlet来实例化Spring IOC容器 - 为什么会有两个不同的类来装载它呢,这是因为它们的使用需要区别不同的Servlet容器支持的Serlvet版本。但不管是 ContextLoaderSevlet还是 ContextLoaderListener都使用ContextLoader来完成实际的WebApplicationContext的初始化工作。这个ContextLoder就像是Spring Web应用程序在Web容器中的加载器booter。当然这些Servlet的具体使用我们都要借助web容器中的部署描述符来进行相关的定义。
    下面我们使用ContextLoaderListener作为载入器作一个详细的分析,这个Servlet的监听器是根上下文被载入的地方,也是整个 Spring web应用加载上下文的第一个地方;从加载过程我们可以看到,首先从Servlet事件中得到ServletContext,然后可以读到配置好的在web.xml的中的各个属性值,然后ContextLoder实例化WebApplicationContext并完成其载入和初始化作为根上下文。当这个根上下文被载入后,它被绑定到web应用程序的ServletContext上。任何需要访问该ApplicationContext的应用程序代码都可以从WebApplicationContextUtils类的静态方法来得到:

    Java代码
    WebApplicationContext getWebApplicationContext(ServletContext sc) 

    以Tomcat作为Servlet容器为例,下面是具体的步骤:
    1.Tomcat 启动时需要从web.xml中读取启动参数,在web.xml中我们需要对ContextLoaderListener进行配置,对于在web应用启动入口是在ContextLoaderListener中的初始化部分;从Spring MVC上看,实际上在web容器中维护了一系列的IOC容器,其中在ContextLoader中载入的IOC容器作为根上下文而存在于 ServletContext中。
    Java代码
    //这里对根上下文进行初始化。  
    public void contextInitialized(ServletContextEvent event) {  
    //这里创建需要的ContextLoader  
    this.contextLoader = createContextLoader();  
    //这里使用ContextLoader对根上下文进行载入和初始化  
    this.contextLoader.initWebApplicationContext(event.getServletContext());  


    通过ContextLoader建立起根上下文的过程,我们可以在ContextLoader中看到:
    Java代码
    public WebApplicationContext initWebApplicationContext(ServletContext servletContext)  
    throws IllegalStateException, BeansException {  
    //这里先看看是不是已经在ServletContext中存在上下文,如果有说明前面已经被载入过,或者是配置文件有错误。  
    if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {  
    //直接抛出异常  
    .........  
    }  

    ...............  
    try {  
    // 这里载入根上下文的父上下文  
    ApplicationContext parent = loadParentContext(servletContext);  

    //这里创建根上下文作为整个应用的上下文同时把它存到ServletContext中去,注意这里使用的ServletContext的属性值是  
    //ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,以后的应用都是根据这个属性值来取得根上下文的 - 往往作为自己上下文的父上下文  
    this.context = createWebApplicationContext(servletContext, parent);  
    servletContext.setAttribute(  
    WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);  
    ..........  

    return this.context;  
    }  
    ............  


    建立根上下文的父上下文使用的是下面的代码,取决于在web.xml中定义的参数:locatorFactorySelector,这是一个可选参数:
    Java代码
    protected ApplicationContext loadParentContext(ServletContext servletContext)  
    throws BeansException {  

    ApplicationContext parentContext = null;  

    String locatorFactorySelector = servletContext.getInitParameter(LOCATOR_FACTORY_SELECTOR_PARAM);  
    String parentContextKey = servletContext.getInitParameter(LOCATOR_FACTORY_KEY_PARAM);  

    if (locatorFactorySelector != null) {  
    BeanFactoryLocator locator = ContextSingletonBeanFactoryLocator.getInstance(locatorFactorySelector);  
    ........  
    //得到根上下文的父上下文的引用  
    this.parentContextRef = locator.useBeanFactory(parentContextKey);  
    //这里建立得到根上下文的父上下文  
    parentContext = (ApplicationContext) this.parentContextRef.getFactory();  
    }  

    return parentContext;  


    得到根上下文的父上下文以后,就是根上下文的创建过程:
    Java代码
    protected WebApplicationContext createWebApplicationContext(  
    ServletContext servletContext, ApplicationContext parent) throws BeansException {  
    //这里需要确定我们载入的根WebApplication的类型,由在web.xml中配置的contextClass中配置的参数可以决定我们需要载入什么样的ApplicationContext,  
    //如果没有使用默认的。  
    Class contextClass = determineContextClass(servletContext);  
    .........  
    //这里就是上下文的创建过程  
    ConfigurableWebApplicationContext wac =  
    (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);  
    //这里保持对父上下文和ServletContext的引用到根上下文中  
    wac.setParent(parent);  
    wac.setServletContext(servletContext);  

    //这里从web.xml中取得相关的初始化参数  
    String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);  
    if (configLocation != null) {  
    wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,  
    ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));  
    }  
    //这里对WebApplicationContext进行初始化,我们又看到了熟悉的refresh调用。  
    wac.refresh();  
    return wac;  


    初始化根ApplicationContext后将其存储到SevletContext中去以后,这样就建立了一个全局的关于整个应用的上下文。这个根上下文会被以后的DispatcherServlet初始化自己的时候作为自己ApplicationContext的父上下文。这个在对 DispatcherServlet做分析的时候我们可以看看到。

    3.完成对ContextLoaderListener的初始化以后,Tomcat开始初始化DispatchServlet,- 还记得我们在web.xml中队载入次序进行了定义。DispatcherServlet会建立自己的ApplicationContext,同时建立这个自己的上下文的时候会从ServletContext中得到根上下文作为父上下文,然后再对自己的上下文进行初始化,并最后存到 ServletContext中去供以后检索和使用。
    可以从DispatchServlet的父类FrameworkServlet的代码中看到大致的初始化过程,整个ApplicationContext的创建过程和ContextLoder创建的过程相类似:
    Java代码
    protected final void initServletBean() throws ServletException, BeansException {  
    .........  
    try {  
    //这里是对上下文的初始化过程。  
    this.webApplicationContext = initWebApplicationContext();  
    //在完成对上下文的初始化过程结束后,根据bean配置信息建立MVC框架的各个主要元素  
    initFrameworkServlet();  
    }  
    ........  


    对initWebApplicationContext()调用的代码如下:
    Java代码
    protected WebApplicationContext initWebApplicationContext() throws BeansException {  
    //这里调用WebApplicationContextUtils静态类来得到根上下文  
    WebApplicationContext parent = WebApplicationContextUtils.getWebApplicationContext(getServletContext());  

    //创建当前DispatcherServlet的上下文,其上下文种类使用默认的在FrameworkServlet定义好的:DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;  
    WebApplicationContext wac = createWebApplicationContext(parent);  
    ........  
    if (isPublishContext()) {  
    //把当前建立的上下文存到ServletContext中去,注意使用的属性名是和当前Servlet名相关的。  
    String attrName = getServletContextAttributeName();  
    getServletContext().setAttribute(attrName, wac);  
    }  
    return wac;  


    其中我们看到调用了WebApplicationContextUtils的静态方法得到根ApplicationContext:
    Java代码
    public static WebApplicationContext getWebApplicationContext(ServletContext sc) {  
    //很简单,直接从ServletContext中通过属性名得到根上下文  
    Object attr = sc.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);  
    .......  
    return (WebApplicationContext) attr;  
    }  
    然后创建DispatcherServlet自己的WebApplicationContext:  
    protected WebApplicationContext createWebApplicationContext(WebApplicationContext parent)  
    throws BeansException {  
    .......  
    //这里使用了BeanUtils直接得到WebApplicationContext,ContextClass是前面定义好的DEFAULT_CONTEXT_CLASS = XmlWebApplicationContext.class;  
    ConfigurableWebApplicationContext wac =  
    (ConfigurableWebApplicationContext) BeanUtils.instantiateClass(getContextClass());  

    //这里配置父上下文,就是在ContextLoader中建立的根上下文  
    wac.setParent(parent);  

    //保留ServletContext的引用和相关的配置信息。  
    wac.setServletContext(getServletContext());  
    wac.setServletConfig(getServletConfig());  
    wac.setNamespace(getNamespace());  

    //这里得到ApplicationContext配置文件的位置  
    if (getContextConfigLocation() != null) {  
    wac.setConfigLocations(  
    StringUtils.tokenizeToStringArray(  
    getContextConfigLocation(), ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));  
    }  

    //这里调用ApplicationContext的初始化过程,同样需要使用refresh()  
    wac.refresh();  
    return wac;  


    4. 然后就是DispatchServlet中对Spring MVC的配置过程,首先对配置文件中的定义元素进行配置 - 请注意这个时候我们的WebApplicationContext已经建立起来了,也意味着DispatcherServlet有自己的定义资源,可以需要从web.xml中读取bean的配置信息,通常我们会使用单独的xml文件来配置MVC中各个要素定义,这里和web容器相关的加载过程实际上已经完成了,下面的处理和普通的Spring应用程序的编写没有什么太大的差别,我们先看看MVC的初始化过程:
    Java代码
    protected void initFrameworkServlet() throws ServletException, BeansException {  
    initMultipartResolver();  
    initLocaleResolver();  
    initThemeResolver();  
    initHandlerMappings();  
    initHandlerAdapters();  
    initHandlerExceptionResolvers();  
    initRequestToViewNameTranslator();  
    initViewResolvers();  


    5. 这样MVC的框架就建立起来了,DispatchServlet对接受到的HTTP Request进行分发处理由doService()完成,具体的MVC处理过程我们在doDispatch()中完成,其中包括使用Command模式建立执行链,显示模型数据等,这些处理我们都可以在DispatcherServlet的代码中看到:
    Java代码
    protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception {  
    ......  
    try {  
    doDispatch(request, response);  
    }  
    .......  


    实际的请求分发由doDispatch(request,response)来完成:
    Java代码
    protected void doDispatch(final HttpServletRequest request, HttpServletResponse response) throws Exception {  
    .......  
    // 这是Spring定义的执行链,里面放了映射关系对应的handler和定义的相关拦截器。  
    HandlerExecutionChain mappedHandler = null;  

    ......  
    try {  
    //我们熟悉的ModelAndView在这里出现了。  
    ModelAndView mv = null;  
    try {  
    processedRequest = checkMultipart(request);  

    //这里更具request中的参数和映射关系定义决定使用的handler  
    mappedHandler = getHandler(processedRequest, false);  

    ......  
    //这里是handler的调用过程,类似于Command模式中的execute.  
    HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());  
    mv = ha.handle(processedRequest, response, mappedHandler.getHandler());  

    .......  
    //这里将模型数据通过视图进行展现  
    if (mv != null && !mv.wasCleared()) {  
    render(mv, processedRequest, response);  
    }  
    ........  


    这样具体的MVC模型的实现就由bean配置文件里定义好的view resolver,handler这些类来实现用户代码的功能。
    总结上面的过程,我们看到在web容器中,ServletContext可以持有一系列的web上下文,而在整个web上下文中存在一个根上下文来作为其它 Servlet上下文的父上下文。这个根上下文是由ContextLoader载入并进行初始化的,对于我们的web应用, DispatcherSerlvet载入并初始化自己的上下文,这个上下文的父上下文是根上下文,并且我们也能从ServletContext中根据 Servlet的名字来检索到我们需要的对应于这个Servlet的上下文,但是根上下文的名字是由Spring唯一确定的。这个 DispactcherServlet建立的上下文就是我们开发Spring MVC应用的IOC容器。
    具体的web请求处理在上下文体系建立完成以后由DispactcherServlet来完成,上面对MVC的运作做了一个大致的描述,下面我们会具体就SpringMVC的框架实现作一个详细的分析。   

    展开全文
  • ServletConfig 是一个接口,它怎样传递给他一格对象来进行初始化呢?其实,是这个对象是由 servlet 容器来实例化的,由容器产生一格 ServletConfig 的实现类的对象,然后传递给 Servlet ②我们有些时候可能在 Servl...
  • jpa接口初始化失败 延迟加载实体之间的关系是JPA中公认的最佳实践。 其主要目标是仅从数据库中检索请求的实体,并仅在需要时加载相关的实体。 如果我们只需要请求的实体,那是一个很好的方法。 但是,如果我们还需要...
  • 初始化: student st1={10, "li ming", 01}; 修改某个成员变量的值:st1.id = 11; 下面谈我遇到的问题:id的接口准备好了,然而不知道name的值,也就是只需要把age和id进行设置就可以了 已经存在的代码 cons...
  • 而且在面试会问到一下关于MyBatis初始化问题,比如: Mybatis需要初始化哪些? MyBatis初始化的过程? MyBatis初始化 在 MyBatis 初始化过程中,会加载 mybatis-config.xml 配置文件、Mapper.xml映射配置文件以及...
  • 有一个接口,这个接口定义了一种规范和标志,接口中只有一个初始化方法,接口的实现类可能会有非常多,需要在容器启动过程中我们去手动初始化这个接口的所有实现类,虽然在spring中我们可以直接配置,但是维护与...
  • item.shop.shopname:''}}因VUE框架问题数据在请求接口里,字段没有初始化{对象里面的对象在初始化里没有找到会报错} 2.目的:在调用接口时同时请求type Return{collectType: 'goods',} //数据初始化 ...
  • 我想点哪个组件,就执行此页面的初始化方法。(之前碰到七个标签页的crud页面,一起调会卡顿)。 解决:用this.$refs[this.activeName].init()调用组件内的初始化方法,而不是放到created。 注意: 用 this. $ ...
  • 本节我们要来解决一下上次遗留的bug,...所以,今天会进行稍微大一点的改来避免这个问题:首先我们还是打开P_cases.html:找到这个监听函数和初始化步骤函数:图中俩处划红线的部分,就是引起我们bug的罪魁祸首。...
  • 获取某接口的所有实现类并初始化

    千次阅读 2018-08-23 16:16:11
     有一个接口,这个接口定义了一种规范和标志,接口中只有一个初始化方法,接口的实现类可能会有非常多,所以现在容器启动过程中我们去手动初始化这个接口的所有实现类,虽然在spring中我们可以直接配置,但是维护与...
  • 1. Spring IOC容器初始化过程:2. bean的生命周期Bean 容器找到配置文件中 Spring Bean 的定义。(beanDefintion)Bean 容器利用 Java Reflection API 创建一个Bean的实例。(执行构造方法)如果涉及到一些属性值 利用...
  • Servlet初始化问题

    2006-08-01 14:26:00
    转自 zhyiwww@163.com  在读我自己的认识之前 , 我们先来看一下 servet 的结构图 : 以下是我自己的一点浅见: ① ... ServletConfig 是一个接口,它怎样传递给他一格对象来进行初始化呢?其实,是这个对象是由 servle
  • Python实例初始化问题

    2020-01-09 11:13:18
    最近在给一个项目写接口自动框架,整体自动测试思路如下: 1、预先生成测试数据(记录对应的测试数据到文件当中) 2、执行测试用例自动执行(将测试过程中新增的数据信息记录到文件当中) 3、测试数据销毁...
  • SpringBoot会将接口初始化放入容器中,SpringFramework不会? 使用SpringBoot2.0.0如下: public interface A { } import org.springframework.stereotype.Service; @Service public class AA implements A{...
  • 想要实现的功能:SSH环境下,数据层都交...系统初始化类需要实现两个接口: ServletContextListener,系统初始化时调用contextInitialized方法缓存数据; ApplicationContextAware,获取Spring的ApplicationContex...
  • 在主程序加载的module中使用某功能需要再加载一为AttriWin的module界面,AttriDataControl为定义好的接口,为名为AttriWin的module实现其定义部分,通过CollectAttributeData初始化AttriWin出错,提示找不到方法或...
  • 调用接口时候,记得不要把接口初始化在全局变量中,否则当接口不通的情况下整个class就都挂了= .=
  • layui数据表格初始化问题

    千次阅读 2019-01-08 18:32:53
    支持【直接从接口请求数据】 注意,在第二个模式下,对入参和出参,有严格限制,甚至对返回数据格式也有要求 建议使用第一种方案 layui.use('table', function(){ var table = layui.table; var config = dp.save...
  • 背景:工作中遇到了调用dubbo服务的场景,项目不是spring项目,我只想简单的调用服务端的接口,不想加入那么多配置。 在服务对接中,遇到调用dubbo服务的场景。按照公司的框架给的开发文档,要加配置!要写注解!不...
  • web程序的初始化问题——ServletContextListener 时间: 2005-01-04 应用ServletContextListener接口,可以实现在web应用程序初始化时,自动运行一些初始化程序。 ServletContextListener接口定义的方
  • 一个解决方法是利用Spring的事件机制,事件机制需要实现ApplicationListener监听器,只要编写一个实现类实现该接口的onApplicationEvent方法,在方法体中初始化应用需要的初始化数据,并做防二次初始化的处理。...
  • ArcGIS Engine许可初始化 ...以Engine9.2为例,应用程序是强制初始化许可,也就是说必须使用LicenseControl或AO接口初始化许可,否则应用程序无法启动。Engine9.1未采取强制初始化许可策略,而是应用程序创...
  • C/C++语言与java不一样java定义一个成员变量时可以不显式初始化系统会在类的准备夹断或者类的实例是进行默认的初始化。java的系统初始化规则是: 整数类型(byte,short,into,long)默认值为0。 浮点类型(float...
  • 今天在看解码程序ffmpeg的时候发现,初始化接口是这么写的:  void avcodec_init(void) { static int initialized = 0; if(initialized != 0) return ; initialized = 1; dsputil_static_init(); } ...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,193
精华内容 877
关键字:

初始化接口问题