标签:
case1)用户输入了正确的username 和 pwd:验证器阀会调用后续的阀;case2)用户输入错误:验证器阀会返回,不会调用后续的阀;
private void createUserDatabase() {// SimpleRealm.createUserDatabase() 创建了users 列表; User user1 = new User("ken", "blackcomb"); user1.addRole("manager"); user1.addRole("programmer"); User user2 = new User("cindy", "bamboo"); user2.addRole("programmer"); users.add(user1); users.add(user2); }
public Principal authenticate (String username, String credentials); // generally used public Principal authenticate (String username, byte[] credentials); public Principal authenticate (String username, String digest, String nonce, String nc, String cnonce, String qop, String realm, String md5a2); public Principal authenticate (X509Certificate cents[]);;3)在catalina中, Realm接口的基本实现形式是org.apache.catalina.realm.RealmBase类;其UML类图如下:
public class GenericPrincipal implements Principal { //org.apache.catalina.realm.GenericPrincipal,代表一个用户(封装了username,password,role,realm) public GenericPrincipal(Realm realm, String name, String password) { this(realm, name, password, null); } public GenericPrincipal(Realm realm, String name, String password, List roles) { super(); this.realm = realm; this.name = name; this.password = password; if (roles != null) { this.roles = new String[roles.size()]; this.roles = (String[]) roles.toArray(this.roles); if (this.roles.length > 0) Arrays.sort(this.roles); } } protected String name = null; public String getName() { return (this.name); } protected String password = null; public String getPassword() { return (this.password); } protected Realm realm = null; public Realm getRealm() { return (this.realm); } protected String roles[] = new String[0]; public String[] getRoles() { return (this.roles); } public boolean hasRole(String role) { // highlight line. if (role == null) return (false); return (Arrays.binarySearch(roles, role) >= 0); } public String toString() { StringBuffer sb = new StringBuffer("GenericPrincipal["); sb.append(this.name); sb.append("]"); return (sb.toString()); } }
step1)如果web.xml 文件包含 login-config 元素的配置,则tomcat会创建一个 LoginConfig对象,并设置其相应属性;(干货——tomcat创建一个 LoginConfig对象的条件)step2)验证器阀会调用 LoginConfig.getRealmName() 获取领域对象名,并将领域对象名发送到 browser,显示在登录对话框中;case2.1)如果getReamlName()方法的返回值是null,则会将服务器名和相应端口发送给 browser;
public final class LoginConfig { //org.apache.catalina.deploy.LoginConfig public LoginConfig() { super(); } public LoginConfig(String authMethod, String realmName, String loginPage, String errorPage) { super(); setAuthMethod(authMethod); setRealmName(realmName); setLoginPage(loginPage); setErrorPage(errorPage); } // ------------------------------------------------------------- Properties private String authMethod = null; public String getAuthMethod() { return (this.authMethod); } public void setAuthMethod(String authMethod) { this.authMethod = authMethod; } private String errorPage = null; public String getErrorPage() { return (this.errorPage); } public void setErrorPage(String errorPage) { this.errorPage = RequestUtil.URLDecode(errorPage); } private String loginPage = null; public String getLoginPage() { return (this.loginPage); } public void setLoginPage(String loginPage) { this.loginPage = RequestUtil.URLDecode(loginPage); } private String realmName = null; public String getRealmName() { return (this.realmName); } public void setRealmName(String realmName) { this.realmName = realmName; } public String toString() { StringBuffer sb = new StringBuffer("LoginConfig["); sb.append("authMethod="); sb.append(authMethod); if (realmName != null) { sb.append(", realmName="); sb.append(realmName); } if (loginPage != null) { sb.append(", loginPage="); sb.append(loginPage); } if (errorPage != null) { sb.append(", errorPage="); sb.append(errorPage); } sb.append("]"); return (sb.toString()); } }
A1)BasicAuthenticator:用来支持基本的身份验证;A2)FormAuthenticator:提供了基于表单的身份验证;A3)DigestAuthenticator:提供了基于信息摘要的身份验证;A4)SSLAuthenticator:用于对SSL 进行身份验证;A5)当tomcat 用户没有指定验证方法名时,NonLoginAuthenticator类用于对来访者的身份进行验证。NonLoginAuthenticator类实现的验证器只会检查安全限制,而不会涉及用户身份的验证;
A1)验证器的重要工作:是对用户进行身份验证;(干货——验证器的重要工作是对用户进行身份验证)A2)当看到 AuthenticatorBase.invoke() 方法调用 authenticate() 抽象方法时:后者的实现依赖于子类;(而authenticate()方法会使用基本身份验证来验证用户的身份信息);
public class BasicAuthenticator extends AuthenticatorBase { <span style="font-family: SimSun;">//org.apache.catalina.authenticator.BasicAuthenticator,这里仅以BasicAuthenticator 为例po出 source code.</span> // ----------------------------------------------------- Instance Variables protected static final Base64 base64Helper = new Base64(); protected static final String info = "org.apache.catalina.authenticator.BasicAuthenticator/1.0"; public String getInfo() { return (this.info); } public boolean authenticate(HttpRequest request, HttpResponse response, LoginConfig config) throws IOException { // Have we already authenticated someone? Principal principal = ((HttpServletRequest) request.getRequest()).getUserPrincipal(); String ssoId = (String) request.getNote(Constants.REQ_SSOID_NOTE); if (principal != null) { if (debug >= 1) log("Already authenticated '" + principal.getName() + "'"); // Associate the session with any existing SSO session if (ssoId != null) associate(ssoId, getSession(request, true)); return (true); } // Is there an SSO session against which we can try to reauthenticate? if (ssoId != null) { if (debug >= 1) log("SSO Id " + ssoId + " set; attempting reauthentication"); if (reauthenticateFromSSO(ssoId, request)) return true; } // Validate any credentials already included with this request HttpServletRequest hreq = (HttpServletRequest) request.getRequest(); HttpServletResponse hres = (HttpServletResponse) response.getResponse(); String authorization = request.getAuthorization(); String username = parseUsername(authorization); String password = parsePassword(authorization); principal = context.getRealm().authenticate(username, password); if (principal != null) { register(request, response, principal, Constants.BASIC_METHOD, username, password); return (true); } // Send an "unauthorized" response and an appropriate challenge String realmName = config.getRealmName(); if (realmName == null) realmName = hreq.getServerName() + ":" + hreq.getServerPort(); hres.setHeader("WWW-Authenticate", "Basic realm=\"" + realmName + "\""); hres.setStatus(HttpServletResponse.SC_UNAUTHORIZED); // hres.flushBuffer(); return (false); } // ------------------------------------------------------ Protected Methods protected String parseUsername(String authorization) { if (authorization == null) return (null); if (!authorization.toLowerCase().startsWith("basic ")) return (null); authorization = authorization.substring(6).trim(); // Decode and parse the authorization credentials String unencoded = new String(base64Helper.decode(authorization.getBytes())); int colon = unencoded.indexOf(':'); if (colon < 0) return (null); String username = unencoded.substring(0, colon); // String password = unencoded.substring(colon + 1).trim(); return (username); } protected String parsePassword(String authorization) { if (authorization == null) return (null); if (!authorization.startsWith("Basic ")) return (null); authorization = authorization.substring(6).trim(); // Decode and parse the authorization credentials String unencoded = new String(base64Helper.decode(authorization.getBytes())); int colon = unencoded.indexOf(':'); if (colon < 0) return (null); // String username = unencoded.substring(0, colon).trim(); String password = unencoded.substring(colon + 1); return (password); } }
A1)若没有设置 auth-method元素:则 LoginConfig 对象 的 atuh-method属性的值默认为 NONE,使用 NonLoginAuthenticator 进行安全验证;A2)由于使用的验证器类是在运行时才确定的,故该类是动态载入的;A3)StandardContext容器使用 org.apahce.catalina.startup.ContextConfig类来对 StandardContext 实例的属性进行设置:这些设置包括 实例化一个验证器类,并将该实例与Context实例相关联;
// Identify the class name of the Valve we should configure String authenticatorName = "org.apache.catalina.authenticator.BasicAuthenticator"; // Instantiate and install an Authenticator of the requested class Valve authenticator = null; try { Class authenticatorClass = Class.forName(authenticatorName); authenticator = (Valve) authenticatorClass.newInstance(); ((StandardContext) context).addValve(authenticator); System.out.println("Added authenticator valve to Context"); } catch (Throwable t) { }
step1)先检查在相关联的Context容器是否有安全限制,若没有直接返回,而不会安装验证器;// Does this Context require an Authenticator? SecurityConstraint constraints[] = context.findConstraints(); if ((constraints == null) || (constraints.length == 0)) return;
step2)若当前Context容器有一个或多个安全限制,authenticatorConfig() 方法会检查该Context实例是否有 LoginConfig对象。若没有,则它会创建一个新的 LoginConfig实例:LoginConfig loginConfig = context.getLoginConfig(); if (loginConfig == null) { loginConfig = new LoginConfig("NONE", null, null, null); context.setLoginConfig(loginConfig); }
step3)检查管道中的基础阀或附加阀是否是验证器。因为一个Context实例只能有一个验证器,所以当发现某个阀是验证器后,直接返回:// Has an authenticator been configured already? Pipeline pipeline = ((StandardContext) context).getPipeline(); if (pipeline != null) { Valve basic = pipeline.getBasic(); if ((basic != null) && (basic instanceof Authenticator)) return; Valve valves[] = pipeline.getValves(); for (int i = 0; i < valves.length; i++) { if (valves[i] instanceof Authenticator) return; } } else { // no Pipeline, cannot install authenticator valve return; }
step4)查找当前Context实例是否有与之关联的领域对象(Realm)。如果没有领域对象,就不需要安装验证器了,因为用户是无法通过身份验证的;// Has a Realm been configured for us to authenticate against? if (context.getRealm() == null) { return; }
step5)若找到了领域对象,则会动态载入 BasicAuthenticator类,创建该类的一个实例,并将其作为阀添加到 StandardContext实例中;// Identify the class name of the Valve we should configure String authenticatorName = "org.apache.catalina.authenticator.BasicAuthenticator"; // Instantiate and install an Authenticator of the requested class Valve authenticator = null; try { Class authenticatorClass = Class.forName(authenticatorName); authenticator = (Valve) authenticatorClass.newInstance(); ((StandardContext) context).addValve(authenticator); System.out.println("Added authenticator valve to Context"); } catch (Throwable t) { } }
public class SimpleRealm implements Realm { public SimpleRealm() { createUserDatabase(); //highlight line. } private void createUserDatabase() { // there are 2 roles. User user1 = new User("ken", "blackcomb"); user1.addRole("manager"); // manager role. user1.addRole("programmer"); // programmer role. User user2 = new User("cindy", "bamboo"); user2.addRole("programmer"); users.add(user1); users.add(user2); // private ArrayList users = new ArrayList(); } }
public Principal authenticate(String username, String credentials) { System.out.println("SimpleRealm.authenticate()"); if (username==null || credentials==null) return null; User user = getUser(username, credentials); if (user==null) return null; return new GenericPrincipal(this, user.username, user.password, user.getRoles()); // highlight line. }
public class GenericPrincipal implements Principal { // 该类封装了用户的一些信息,如username,pass,role,realm等info; public GenericPrincipal(Realm realm, String name, String password) { this(realm, name, password, null); } public GenericPrincipal(Realm realm, String name, String password, List roles) { super(); this.realm = realm; this.name = name; this.password = password; if (roles != null) { this.roles = new String[roles.size()]; this.roles = (String[]) roles.toArray(this.roles); if (this.roles.length > 0) Arrays.sort(this.roles); } } protected String name = null; public String getName() { return (this.name); } protected String password = null; public String getPassword() { return (this.password); } protected Realm realm = null; public Realm getRealm() { return (this.realm); } protected String roles[] = new String[0]; public String[] getRoles() { return (this.roles); } public boolean hasRole(String role) { if (role == null) return (false); return (Arrays.binarySearch(roles, role) >= 0); } public String toString() { StringBuffer sb = new StringBuffer("GenericPrincipal["); sb.append(this.name); sb.append("]"); return (sb.toString()); } }
// tomcat-users.xml 的源码如下: <?xml version='1.0' encoding='utf-8'?> <tomcat-users> <role rolename="tomcat"/> <role rolename="role1"/> <role rolename="manager"/> <role rolename="admin"/> <user username="tomcat" password="tomcat" roles="tomcat"/> <user username="role1" password="tomcat" roles="role1"/> <user username="both" password="tomcat" roles="tomcat,role1"/> <user username="admin" password="admin" roles="admin,manager"/> </tomcat-users>
// 以下代码是 Bootstrap2.java 中的源码 Realm realm = new SimpleUserDatabaseRealm(); String filedir = new File(System.getProperty("user.dir")).getParent() + File.separator + "conf" + File.separator + "tomcat-users.xml"; ((SimpleUserDatabaseRealm) realm).createDatabase(filedir); // highlight line.
public void createDatabase(String path) { // SimpleUserDatabaseRealm.createDatabase(). database = new MemoryUserDatabase(name); ((MemoryUserDatabase) database).setPathname(path); try { database.open(); // highlight line. } catch (Exception e) { } }
public void open() throws Exception { // org.apache.catalina.users.MemoryUserDatabase.open(). synchronized (groups) { synchronized (users) { // Erase any previous groups and users users.clear(); groups.clear(); roles.clear(); // Construct a reader for the XML input file (if it exists) File file = new File(pathname); if (!file.isAbsolute()) { file = new File(System.getProperty("catalina.base"), pathname); } if (!file.exists()) { return; } FileInputStream fis = new FileInputStream(file); // Construct a digester to read the XML input file Digester digester = new Digester(); digester.addFactoryCreate ("tomcat-users/group", new MemoryGroupCreationFactory(this)); digester.addFactoryCreate ("tomcat-users/role", new MemoryRoleCreationFactory(this)); digester.addFactoryCreate ("tomcat-users/user", new MemoryUserCreationFactory(this)); // Parse the XML input file to load this database try { digester.parse(fis); fis.close(); } catch (Exception e) { try { fis.close(); } catch (Throwable t) { ; } throw e; } } } }
public final class Bootstrap1 { public static void main(String[] args) { //invoke: http://localhost:8080/Modern or http://localhost:8080/Primitive System.setProperty("catalina.base", System.getProperty("user.dir")); System.out.println("user.dir = " + System.getProperty("user.dir")); Connector connector = new HttpConnector(); Wrapper wrapper1 = new SimpleWrapper(); wrapper1.setName("Primitive"); wrapper1.setServletClass("servlet.PrimitiveServlet"); Wrapper wrapper2 = new SimpleWrapper(); wrapper2.setName("Modern"); wrapper2.setServletClass("servlet.ModernServlet"); Context context = new StandardContext(); // highlight line. // StandardContext's start method adds a default mapper context.setPath("/myApp"); context.setDocBase("myApp"); LifecycleListener listener = new SimpleContextConfig();// highlight line. ((Lifecycle) context).addLifecycleListener(listener); context.addChild(wrapper1); context.addChild(wrapper2); // for simplicity, we don't add a valve, but you can add // valves to context or wrapper just as you did in Chapter 6 Loader loader = new WebappLoader(); context.setLoader(loader); // context.addServletMapping(pattern, name); context.addServletMapping("/Primitive", "Primitive"); context.addServletMapping("/Modern", "Modern"); // add ContextConfig. This listener is important because it configures // StandardContext (sets configured to true), otherwise StandardContext // won't start // add constraint SecurityCollection securityCollection = new SecurityCollection();// highlight line. securityCollection.addPattern("/");// highlight line. securityCollection.addMethod("GET");// highlight line. SecurityConstraint constraint = new SecurityConstraint();// highlight line. constraint.addCollection(securityCollection);// highlight line. constraint.addAuthRole("manager");// highlight line. LoginConfig loginConfig = new LoginConfig();// highlight line. loginConfig.setRealmName("Simple Realm"); // add realm Realm realm = new SimpleRealm();// highlight line. context.setRealm(realm);// highlight line. context.addConstraint(constraint);// highlight line. context.setLoginConfig(loginConfig);// highlight line. connector.setContainer(context); // add a Manager Manager manager = new StandardManager(); context.setManager(manager); try { connector.initialize(); ((Lifecycle) connector).start(); ((Lifecycle) context).start(); // make the application wait until we press a key. System.in.read(); ((Lifecycle) context).stop(); } catch (Exception e) { e.printStackTrace(); } } }
A1)创建StandardContext对象:设置其path属性和 documentBase属性,并添加一个 SimpleContextConfig 类的监听器。该监听器会把一个 BasicAuthenticator 对象安装到 StandardContext 对象中;A2)创建SecurityColleciton对象:并调用其addPattern和 addMethod方法,addPattern方法指定某个url 要遵循哪个安全限制, 而addMethod方法会指定该安全限制要使用哪种验证方法;在addMethod()方法中设置为GET, 则使用GET 方法提交的http 请求会遵循安全限制;A3)创建 SecurityManager对象:并将其添加到 安全限制集合中,且还设置了哪种角色可以访问这些受限资源。A4)创建LoginConfig对象 和 SimpleRealm对象;A5)将领域对象,安全限制对象,登录配置对象 与 StandardContext实例相关联;A6)接着,启动Context实例。。。。。。。
<pre name="code" class="java">E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src>java -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;lib/catalina-5.5.4.jar;lib/naming-common jar;lib/commons-collections.jar;lib/naming-resources.jar;lib/;lib/catalina.jar;E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\webroot com.tomc t.chapter10.startup.Bootstrap1 HttpConnector Opening server socket on all host IP addresses HttpConnector[8080] Starting background thread WebappLoader[/myApp]: Deploying class repositories to work directory E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src\work\_\_\myApp Starting Wrapper Primitive Starting Wrapper Modern Added authenticator valve to Context StandardManager[/myApp]: Seeding random number generator class java.security.SecureRandom StandardManager[/myApp]: Seeding of random number generator has been completed StandardManager[/myApp]: IOException while loading persisted sessions: java.io.EOFException // 这是从文件中加载 session对象到内存,由于没有相关文件,所以加载失败,抛出异常,但这不会影响我们访问servlet,大家不要惊慌; java.io.EOFException at java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source) at java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source) at java.io.ObjectInputStream.readStreamHeader(Unknown Source) at java.io.ObjectInputStream.<init>(Unknown Source) at org.apache.catalina.util.CustomObjectInputStream.<init>(CustomObjectInputStream.java:103) at org.apache.catalina.session.StandardManager.load(StandardManager.java:408) at org.apache.catalina.session.StandardManager.start(StandardManager.java:655) at org.apache.catalina.core.StandardContext.start(StandardContext.java:3570) at com.tomcat.chapter10.startup.Bootstrap1.main(Bootstrap1.java:84) StandardManager[/myApp]: Exception loading sessions from persistent storage java.io.EOFException at java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source) at java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source) at java.io.ObjectInputStream.readStreamHeader(Unknown Source) at java.io.ObjectInputStream.<init>(Unknown Source) at org.apache.catalina.util.CustomObjectInputStream.<init>(CustomObjectInputStream.java:103) at org.apache.catalina.session.StandardManager.load(StandardManager.java:408) at org.apache.catalina.session.StandardManager.start(StandardManager.java:655) at org.apache.catalina.core.StandardContext.start(StandardContext.java:3570) at com.tomcat.chapter10.startup.Bootstrap1.main(Bootstrap1.java:84) SimpleRealm.authenticate() SimpleRealm.authenticate() ModernServlet -- init SimpleRealm.authenticate() SimpleRealm.authenticate() SimpleRealm.authenticate() SimpleRealm.authenticate() SimpleRealm.authenticate() SimpleRealm.authenticate() init SimpleRealm.authenticate() from service from service
public final class Bootstrap2 { public static void main(String[] args) { //invoke: http://localhost:8080/Modern or http://localhost:8080/Primitive System.setProperty("catalina.base", System.getProperty("user.dir")); Connector connector = new HttpConnector(); Wrapper wrapper1 = new SimpleWrapper(); wrapper1.setName("Primitive"); wrapper1.setServletClass("servlet.PrimitiveServlet"); Wrapper wrapper2 = new SimpleWrapper(); wrapper2.setName("Modern"); wrapper2.setServletClass("servlet.ModernServlet"); Context context = new StandardContext(); // highlight line. // StandardContext's start method adds a default mapper context.setPath("/myApp"); context.setDocBase("myApp"); LifecycleListener listener = new SimpleContextConfig();// highlight line. ((Lifecycle) context).addLifecycleListener(listener); context.addChild(wrapper1); context.addChild(wrapper2); // for simplicity, we don't add a valve, but you can add // valves to context or wrapper just as you did in Chapter 6 Loader loader = new WebappLoader(); context.setLoader(loader); // context.addServletMapping(pattern, name); context.addServletMapping("/Primitive", "Primitive"); context.addServletMapping("/Modern", "Modern"); // add ContextConfig. This listener is important because it configures // StandardContext (sets configured to true), otherwise StandardContext // won't start // add constraint SecurityCollection securityCollection = new SecurityCollection();// highlight line. securityCollection.addPattern("/");// highlight line. securityCollection.addMethod("GET");// highlight line. SecurityConstraint constraint = new SecurityConstraint();// highlight line. constraint.addCollection(securityCollection);// highlight line. constraint.addAuthRole("manager");// highlight line. constraint.addAuthRole("tomcat");// highlight line.注意这里的角色,必要要和tomcat-users.xml 中的users 列表相对应,如果要设置某个用户有权限访问servlet资源,则需要添加其所属的角色; LoginConfig loginConfig = new LoginConfig();// highlight line. loginConfig.setRealmName("Simple User Database Realm"); // add realm Realm realm = new SimpleUserDatabaseRealm();// highlight line. String filedir = new File(System.getProperty("user.dir")).getParent() + File.separator + "conf" + File.separator + "tomcat-users.xml"; ((SimpleUserDatabaseRealm) realm).createDatabase(filedir); // highlight line.设置tomcat-users.xml 的文件路径 以载入其内容到内存进行身份验证工作; context.setRealm(realm);// highlight line. context.addConstraint(constraint);// highlight line. context.setLoginConfig(loginConfig);// highlight line. connector.setContainer(context); try { connector.initialize(); ((Lifecycle) connector).start(); ((Lifecycle) context).start(); // make the application wait until we press a key. System.in.read(); ((Lifecycle) context).stop(); } catch (Exception e) { e.printStackTrace(); } }}
// tomcat-users.xml 的源码如下: <?xml version='1.0' encoding='utf-8'?> <tomcat-users> <role rolename="tomcat"/> <role rolename="role1"/> <role rolename="manager"/> <role rolename="admin"/> <user username="tomcat" password="tomcat" roles="tomcat"/> <user username="role1" password="tomcat" roles="role1"/> <user username="both" password="tomcat" roles="tomcat,role1"/> <user username="admin" password="admin" roles="admin,manager"/> </tomcat-users>
E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src>java -cp .;lib/servlet.jar;lib/catalina_4_1_24.jar;lib/catalina-5.5.4.jar;lib/naming-common. jar;lib/commons-collections.jar;lib/naming-resources.jar;lib/;lib/catalina.jar;lib\commons-digester.jar;lib\commons-logging.jar;E:\bench-cluster\cloud -data-preprocess\HowTomcatWorks\webroot com/tomcat/chapter10/startup/Bootstrap2 HttpConnector Opening server socket on all host IP addresses HttpConnector[8080] Starting background thread WebappLoader[/myApp]: Deploying class repositories to work directory E:\bench-cluster\cloud-data-preprocess\HowTomcatWorks\src\work\_\_\myApp Starting Wrapper Primitive Starting Wrapper Modern Added authenticator valve to Context StandardManager[/myApp]: Seeding random number generator class java.security.SecureRandom StandardManager[/myApp]: Seeding of random number generator has been completed StandardManager[/myApp]: IOException while loading persisted sessions: java.io.EOFException // 这是从文件中加载 session对象到内存,由于没有相关文件,所以加载失败,抛出异常,但这不会影响我们访问servlet,大家不要惊慌; java.io.EOFException at java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source) at java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source) at java.io.ObjectInputStream.readStreamHeader(Unknown Source) at java.io.ObjectInputStream.<init>(Unknown Source) at org.apache.catalina.util.CustomObjectInputStream.<init>(CustomObjectInputStream.java:103) at org.apache.catalina.session.StandardManager.load(StandardManager.java:408) at org.apache.catalina.session.StandardManager.start(StandardManager.java:655) at org.apache.catalina.core.StandardContext.start(StandardContext.java:3570) at com.tomcat.chapter10.startup.Bootstrap2.main(Bootstrap2.java:84) StandardManager[/myApp]: Exception loading sessions from persistent storage java.io.EOFException at java.io.ObjectInputStream$PeekInputStream.readFully(Unknown Source) at java.io.ObjectInputStream$BlockDataInputStream.readShort(Unknown Source) at java.io.ObjectInputStream.readStreamHeader(Unknown Source) at java.io.ObjectInputStream.<init>(Unknown Source) at org.apache.catalina.util.CustomObjectInputStream.<init>(CustomObjectInputStream.java:103) at org.apache.catalina.session.StandardManager.load(StandardManager.java:408) at org.apache.catalina.session.StandardManager.start(StandardManager.java:655) at org.apache.catalina.core.StandardContext.start(StandardContext.java:3570) at com.tomcat.chapter10.startup.Bootstrap2.main(Bootstrap2.java:84) ModernServlet -- init
标签:
原文地址:http://blog.csdn.net/pacosonswjtu/article/details/51253679