使用JDK动态代理时为何必须实现至少一个接口

这个问题,就要去看一下OpenJDK的源码了:

//在Proxy类里中:
//constructorParams的定义如下:
private static final Class<?>[] constructorParams = { InvocationHandler.class };

//newProxyInstance无限精简之后就是:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
        throws IllegalArgumentException {
    //通过ProxyClassFactory调用ProxyGenerator生成了代理类
    Class<?> cl = getProxyClass0(loader, interfaces);
    //找到参数为InvocationHandler.class的构造函数
    final Constructor<?> cons = cl.getConstructor(constructorParams);
    //创建代理类实例
    return cons.newInstance(new Object[]{h});
}

//在ProxyGenerator类中:
public static byte[] generateProxyClass(final String name,Class<?>[] interfaces, int accessFlags)){}
private byte[] generateClassFile() {}

//上面两个方法,做的就是:
//将接口全部进行代理
//并生成其他需要的方法,比如上面用到的构造函数、toString、equals、hashCode等
//生成对应的字节码
//其实这也就说明了,为何JDK的动态代理,必须需要至少一个接口

Jetty源码分析01

一、Jetty的ScopedHandler的doStart方法,最后一步是将线程私有变量__outerScope设置成null,为什么需要这样做呢?

protected void doStart() throws Exception
{
    try{
        _outerScope=__outerScope.get();
        if (_outerScope==null){
           //本次处理的第一个scope handler
           //告知后续scope handler,_outerScope选我
            __outerScope.set(this);
        }
        super.doStart();
        _nextScope= getChildHandlerByClass(ScopedHandler.class);
    }
    finally
    {
        if (_outerScope==null){
           //本次处理结束
           //为了下次同一个线程处理是,
           //还能正常的设置第一个scope handler
           //必须把threadlocal变量设为null
            __outerScope.set(null);
        }
    }
}

二、Jetty中,ScopedHandler中nextHandle调用顺序是如何的?

//此外,这一节里有一个non scoped handler X,一开始没太看懂调阅顺序。
//后来发现是这样的:
public final void nextHandle(String target...)...
{
    if (_nextScope!=null && _nextScope==_handler){
        //上面条件可以保证下一个handler是scope handler
        _nextScope.doHandle(target,baseRequest,request, response);
    }
    else if (_handler!=null){
        //non scpoe handler调用下一个handler的
        super.handle(target,baseRequest,request,response);
    }
}

感觉类成员的命名不太合适,
比如__outerScope和_outerScope
比如_handler其实一直指向的是下一个handler,是不是该为_nextHandler更好一些?

Java的各种容器

对比一下,Servlet容器、Spring容器和SpringMVC容器。

Servlet容器,是用于管理Servlet生命周期的。
Spring容器,是用于管理Spring Bean生命周期的。
SpringMVC容器,适用于管理SpringMVC Bean生命周期的。

Tomcat/Jetty启动,对于每个WebApp,依次进行初始化工作:
1、对每个WebApp,都有一个WebApp ClassLoader,和一个ServletContext
2、ServletContext启动时,会扫描web.xml配置文件,找到Filter、Listener和Servlet配置

3、如果Listener中配有spring的ContextLoaderListener
3.1、ContextLoaderListener就会收到webapp的各种状态信息。
3.3、在ServletContext初始化时,ContextLoaderListener也就会将Spring IOC容器进行初始化,管理Spring相关的Bean。
3.4、ContextLoaderListener会将Spring IOC容器存放到ServletContext中

4、如果Servlet中配有SpringMVC的DispatcherServlet
4.1、DispatcherServlet初始化时(其一次请求到达)。
4.2、其中,DispatcherServlet会初始化自己的SpringMVC容器,用来管理Spring MVC相关的Bean。
4.3、SpringMVC容器可以通过ServletContext获取Spring容器,并将Spring容器设置为自己的根容器。而子容器可以访问父容器,从而在Controller里可以访问Service对象,但是在Service里不可以访问Controller对象。
4.2、初始化完毕后,DispatcherServlet开始处理MVC中的请求映射关系。

我面试的时候,有段时间经常会问一个很坑问题,Servlet默认是单例模式的,Spring的Bean默认是单例模式的,那Spring MVC是如何处理并发请求的呢?

Servlet容器、Spring容器、SpringMVC容器之间的关系

之前在极客时间上回答老师的问题:

Servlet容器,是用于管理Servlet生命周期的。
Spring容器,是用于管理Spring Bean生命周期的。
SpringMVC容器,适用于管理SpringMVC Bean生命周期的。

Tomcat/Jetty启动,对于每个WebApp,依次进行初始化工作:
1、对每个WebApp,都有一个WebApp ClassLoader,和一个ServletContext
2、ServletContext启动时,会扫描web.xml配置文件,找到Filter、Listener和Servlet配置

3、如果Listener中配有Spring的ContextLoaderListener
3.1、ContextLoaderListener就会收到webapp的各种状态信息。
3.3、在ServletContext初始化时,ContextLoaderListener也就会将Spring IOC容器进行初始化,管理Spring相关的Bean。
3.4、ContextLoaderListener会将Spring IOC容器存放到ServletContext中

4、如果Servlet中配有SpringMVC的DispatcherServlet
4.1、DispatcherServlet初始化时(其一次请求到达)。
4.2、其中,DispatcherServlet会初始化自己的SpringMVC容器,用来管理Spring MVC相关的Bean。
4.3、SpringMVC容器可以通过ServletContext获取Spring容器,并将Spring容器设置为自己的根容器。而子容器可以访问父容器,从而在Controller里可以访问Service对象,但是在Service里不可以访问Controller对象。
4.2、初始化完毕后,DispatcherServlet开始处理MVC中的请求映射关系。

HBase简单通讯代码

首先,就要说一下配置问题了。HBase客户端的配置有两种方式,一种是通过配置文件,另一种是通过代码设置。

1、配置文件方式
配置文件名称为hbase-site.xml,该文件必须放置到CLASS_PATH下面才会有效,文件示例如下:
hbase-site.xml

<?xml version="1.0"?>
<?xml-stylesheet type="text/xsl" href="configuration.xsl"?>
<configuration>
	<property>
		<name>hbase.rootdir</name>
		<value>hdfs://hadoop-master:9000/hbase</value>
	</property>
	<property>
		<name>hbase.cluster.distributed</name>
		<value>true</value>
	</property>
	<property>
		<name>hbase.master</name>
		<value>hdfs://hadoop-master:60000</value>
	</property>
	<property>
		<name>hbase.zookeeper.quorum</name>
		<value>hadoop-master,hadoop-slave01,hadoop-slave02</value>
	</property>
</configuration>

2、通过代码配置方式

        Configuration hbaseConfig = HBaseConfiguration.create();
        hbaseConfig.setInt("timeout", 120000);
        hbaseConfig.set("hbase.master", "hdfs://hadoop-master:60000");
        hbaseConfig.set("hbase.zookeeper.quorum", "hadoop-master,hadoop-slave01,hadoop-slave02");
        hbaseConfig.setInt("hbase.zookeeper.property.clientPort", 2181);
        hbaseConfig.setInt("hbase.client.retries.number", 1);

Continue reading HBase简单通讯代码

eXistDB简单通讯12(HTTP_SOAP)

  • 保存文件
  • 取回文件
  • 查询

1、QueryFileSOAP.java

package com.neohope.existdb.test;

import org.exist.soap.Query;
import org.exist.soap.QueryResponse;
import org.exist.soap.QueryService;
import org.exist.soap.QueryServiceLocator;

import java.net.URL;
import java.nio.charset.Charset;

public class QueryFileSOAP {
    public static void QueryXML(String xquery, String user, String pwd) throws Exception {
        QueryService service = new QueryServiceLocator();
        Query query = service.getQuery(new URL("http://localhost:8080/exist/services/Query"));
        String sessionId = query.connect("neotest", "neotest");

        byte[] queryData = xquery.getBytes(Charset.forName("UTF-8"));
        QueryResponse resp = query.xquery( sessionId, queryData );
        System.out.println( "found: " + resp.getHits() );
        if(resp.getHits() == 0) {
            return;
        }
        else {
            //get 10 results
            byte[][] hits = query.retrieveData(sessionId, 1, 10,
                    true, false, "elements").getElements();
            for (int i = 0; i < hits.length; i++) {
                System.out.println(new String(hits[i], "UTF-8"));
            }
        }

        query.disconnect(sessionId);
    }

    public static void main(String args[]) throws Exception {
        String user = "neotest";
        String pwd = "neotest";
        String query ="for $name in collection('/db/CDA')/ClinicalDocument/recordTarget/patientRole/patient/name \n" +
                "return \n" +
                "<name>{$name}</name> ";
        QueryXML(query, user, pwd);
    }
}

eXistDB简单通讯11(HTTP_SOAP)

  • 保存文件
  • 取回文件
  • 查询

1、GetFileSOAP.java

package com.neohope.existdb.test;

import org.exist.soap.Query;
import org.exist.soap.QueryService;
import org.exist.soap.QueryServiceLocator;

import java.net.URL;


public class GetFileSOAP {
    public static void GetXML(String fileId, String user, String pwd) throws Exception {
        QueryService service = new QueryServiceLocator();
        Query query = service.getQuery(new URL("http://localhost:8080/exist/services/Query"));
        String session = query.connect(user, pwd);

        byte[] data = query.getResourceData(session,
                "/db/CDA/"+fileId,
                true, false, false);
        System.out.println(new String(data, "UTF-8"));
        query.disconnect(session);
    }

    public static void main(String args[]) throws Exception {
        String user = "neotest";
        String pwd = "neotest";
        GetXML("入院患者护理评估单01.xml",user,pwd);
    }
}

eXistDB简单通讯10(HTTP_SOAP)

  • 保存文件
  • 取回文件
  • 查询

1、SaveFileSOAP.java

package com.neohope.existdb.test;

import org.exist.soap.*;

import java.io.BufferedReader;
import java.io.FileReader;
import java.net.URL;
import java.nio.charset.Charset;

public class SaveFileSOAP {
    public static void SaveXML(String xmlFilePath, String user, String pwd) throws Exception {
        AdminService adminService = new AdminServiceLocator();
        Admin admin = adminService.getAdmin(new URL("http://localhost:8080/exist/services/Admin"));
        String session = admin.connect("neotest", "neotest");

        BufferedReader f = new BufferedReader(new FileReader(xmlFilePath));
        String line;
        StringBuffer xml = new StringBuffer();
        while ((line = f.readLine()) != null)
            xml.append(line);
        f.close();

        admin.store(session, xml.toString().getBytes(Charset.forName("UTF-8")), "UTF-8", "/db/CDA/入院患者护理评估单02.xml", true);
        admin.disconnect(session);
    }

    public static void main( String[] args ) throws Exception {
        String user = "neotest";
        String pwd = "neotest";
        SaveXML("PATH_TO_FILE\\入院患者护理评估单02.xml", user, pwd);
    }
}

eXistDB简单通讯09(HTTP_REST)

  • 保存文件
  • 取回文件
  • 查询

1、QueryFileHTTP.java

package com.neohope.existdb.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.Charset;

public class QueryFileHTTP {
    public static void QueryXML(String query) throws IOException {
        URL url = new URL("http://localhost:8080/exist/rest/db/CDA");
        HttpURLConnection connect = (HttpURLConnection) url.openConnection();
        connect.setRequestProperty("Content-Type", "application/xml");
        connect.setRequestMethod("POST");
        connect.setDoOutput(true);

        OutputStream os = connect.getOutputStream();
        os.write(query.getBytes(Charset.forName("UTF-8")));
        connect.connect();

        BufferedReader is = new BufferedReader(new InputStreamReader(connect.getInputStream()));
        String line;
        while((line = is.readLine()) != null)
            System.out.println(line);
    }

    public static void main(String[] args) throws IOException {
        String query ="<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
                "<query xmlns=\"http://exist.sourceforge.net/NS/exist\" start=\"1\" max=\"10\" cache=\"no\">\n";
        query +="<text><![CDATA[\n" +
                "for $name01 in /ClinicalDocument/recordTarget/patientRole/patient/name \n" +
                "return \n" +
                "<name>{$name01}</name> \n" +
                "]]></text> \n";
        query +="<properties> \n";
        query +="<property name=\"indent\" value=\"yes\"/> \n";
        query +="<property name=\"encoding\" value=\"UTF-8\"/> \n";
        query +="</properties> \n";
        query +="</query>";
        System.out.println(query);
        QueryXML(query);
    }
}