错误javax.servlet.ServletException: Servlet.init() for servlet com.hank.controller.UserLogin threw exception的解决:
背景
在写Spring的时候init()方法脑热写出来的错误:
浏览器错误提示:
错误日志:
exception
javax.servlet.ServletException: Servlet.init() for servlet com.hank.controller.UserLogin threw exception
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:962)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:445)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1115)
org.apache.coyote.AbstractProtocol
A
b
s
t
r
a
c
t
C
o
n
n
e
c
t
i
o
n
H
a
n
d
l
e
r
.
p
r
o
c
e
s
s
(
A
b
s
t
r
a
c
t
P
r
o
t
o
c
o
l
.
j
a
v
a
:
637
)
o
r
g
.
a
p
a
c
h
e
.
t
o
m
c
a
t
.
u
t
i
l
.
n
e
t
.
J
I
o
E
n
d
p
o
i
n
t
AbstractConnectionHandler.process(AbstractProtocol.java:637) org.apache.tomcat.util.net.JIoEndpoint
AbstractConnectionHandler.process(AbstractProtocol.java:637)org.apache.tomcat.util.net.JIoEndpointSocketProcessor.run(JIoEndpoint.java:318)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
java.util.concurrent.ThreadPoolExecutor
W
o
r
k
e
r
.
r
u
n
(
T
h
r
e
a
d
P
o
o
l
E
x
e
c
u
t
o
r
.
j
a
v
a
:
624
)
o
r
g
.
a
p
a
c
h
e
.
t
o
m
c
a
t
.
u
t
i
l
.
t
h
r
e
a
d
s
.
T
a
s
k
T
h
r
e
a
d
Worker.run(ThreadPoolExecutor.java:624) org.apache.tomcat.util.threads.TaskThread
Worker.run(ThreadPoolExecutor.java:624)org.apache.tomcat.util.threads.TaskThreadWrappingRunnable.run(TaskThread.java:61)
java.lang.Thread.run(Thread.java:748)
root cause
java.lang.ClassCastException: com.sun.proxy.Proxy127 cannot be cast to com.hank.service.Imp.UserServiceImp
com.hank.controller.UserLogin.init(UserLogin.java:29)
javax.servlet.GenericServlet.init(GenericServlet.java:158)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:506)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:962)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:445)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1115)
org.apache.coyote.AbstractProtocolAbstractConnectionHandler.process(AbstractProtocol.java:637)
org.apache.tomcat.util.net.JIoEndpointSocketProcessor.run(JIoEndpoint.java:318)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
java.util.concurrent.ThreadPoolExecutorWorker.run(ThreadPoolExecutor.java:624)
org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
java.lang.Thread.run(Thread.java:748)
错误代码:
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
userService = (UserServiceImp) ac.getBean("userservice");
错误原因分析:
因为aop底层默认是jdk动态代理的方式,而jdk动态代理是基于接口来实现的。生成的代理对象和真实对象的关系是实现一样的方法接口的平级关系。对于平级之间的强转这是很显然是错误的。
解决方案1
把生成的代理对象修改为强转为接口使用接口来获得代理对象的引用。
private UserService userService;
@Override
public void init() throws ServletException {
// ApplicationContext ac = WebApplicationContextUtils.getWebApplicationContext(this.getServletContext());
ApplicationContext ac = new ClassPathXmlApplicationContext("application.xml");
userService = (UserService) ac.getBean("userservice");
解决方案2
开启aop的cglib动态代理方式:因为cglib动态代理是基于继承的方式来实现获得代理对象,因此获得代理对象和真实对象的关系是继承关系。因此可以强转。
开启步骤:
-
导入cglib的jar:
.2.在s’pring的配置开启cglib动态代理
<!-- 开启cjlib代理 基于继承-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
总结aop底层两种代理方式:
1、jdk动态代理
原理:jdk动态代理基于接口的代理方式,动态生成的代理对象和真实对象实现同一接口。调用JDK官方的类文件获取动态生产的代理对象。
public class Myjdk implements InvocationHandler {//实现InvocationHandler接口
/**
* 参数分析:
*
* Object proxy 代理对象
* Method method 代理的方法对象
* Object[] args 储存代理方法接受的实参的数组
* */
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("扩展前");
Student student = new Student();
student.show();
System.out.println("扩展后");
return null;
}
}
// jdk动态代理
MyInter myInter = (MyInter) Proxy.newProxyInstance(
test.class.getClassLoader(),//类加载器,加载动态生产的代理对象
new Class[]{MyInter.class}, //动态生产的代理对象要实现的接口
new Myjdk());//动态生成的 代理对象自动调用的扩展代码invocationHandler接口实现的
myInter.show();//调用动态生成的代理对象的方法
2、cjlib动态代理
基于继承的方式来动态生成代理对象。需要导入cjlib 的jar,实现MethodInterceptor 接口
import net.sf.cglib.proxy.MethodInterceptor;
import java.lang.reflect.Method;
public class MyStudent implements MethodInterceptor {
/**
* 参数分析:
*
* Object o 代理对象
* Method method 真实方法对象
* Object[] objects 储存了代理方法接收的实参数组
* net.sf.cglib.proxy.MethodProxy methodProxy 代理方法对象
* */
@Override
public Object intercept(Object o, Method method, Object[] objects, net.sf.cglib.proxy.MethodProxy methodProxy) throws Throwable {
System.out.println("cglib代理前");
methodProxy.invokeSuper(o,objects);//使用反射
System.out.println("cglib代理后");
return null;
}
}
Cglib调用:
import com.aop6_cglib.cglib.MyStudent;
import com.aop6_cglib.pojo.Student;
import net.sf.cglib.proxy.Enhancer;
public class test {
public static void main(String[] args) {
//cglib代理===》继承
Enhancer enhancer = new Enhancer();//创建cglib对象
enhancer.setSuperclass(Student.class);//设置生成代理对象所要继承的对象
enhancer.setCallback(new MyStudent());//设置生成的代理对象的代理方法所执行的代码
Student o = (Student) enhancer.create();//生成代理对象
o.show();
}
}
博主温馨提示:
如果你想练习这个层实现,导包别导错了。
jdk上面案例代码的包路径:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
cglib上面案例代码的包路径:
import net.sf.cglib.proxy.MethodInterceptor;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
现在因为一些缘故,导致几个月说的Java日笔记总结不能按时发布。但是以后博主我以后会找时间补上javase的笔记。如果大家觉得有帮助就关注一下博主吧。