Today in writing Spring
of introducing the agent when a reported error:
Exception in thread "main" org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'inter1' is expected to be of type 'com.dengchengchao.springtest.intertest.Inter1Impl' but was actually of type 'com.sun.proxy.$Proxy14'
Probably means that type conversion error.
Source code is as follows:
ApplicationContext ctx = new AnnotationConfigApplicationContext(Conf.class);
Inter1 inter1 = ctx.getBean("inter1", Inter1Impl.class);
inter1.say1();
Inter2 inter2=(Inter2) inter1;
inter2.say2();
Later, google
a little way into the agent found the CGLIB
line.
We all know the JDK
only agent interface, for a class of non-agent interfaces, it should be used CGLIB
.
Because CGLIB
a proxy class through inheritance to achieve, and JDK
is achieved by interface.
But I am here Inter1
clearly is an interface. Later, double-check code, in fact, found that the use of Java
a proxy is also OK, as long as the change the following line of code:
Inter1 inter1 = ctx.getBean("inter1", Inter1.class);
In other words, needs to be converted into type should be Inter1.class
and can not be specific class Inter1Impl
.
Why Java
proxy only supports interface agent , here we come Grilled deep look:
First, we define an interface:
public interface People {
void eat();
}
Then define an implementation class:
public class Student implements People{
@Override
public void eat() {
System.out.println("用手吃");
}
}
We then define a proxy class:
public class StudentInvokeHandler implements InvocationHandler {
private Object target;
public StudentInvokeHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("饭前洗手");
Object retVal = method.invoke(target, args);
System.out.println("饭后吃水果");
return retVal;
}
}
Next, through a proxy to callStudent
public static void main(String[] args) {
//初始化Student
Student student = new Student();
//初始化Student代理类
StudentInvokeHandler studentInvokeHandler = new StudentInvokeHandler(student);
//通过代理获取代理独享
People studentProxy = (People) Proxy.newProxyInstance(StudentInvokeHandler.class.getClassLoader(), new Class[]{People.class}, studentInvokeHandler);
//通过代理对象调用eat方法
studentProxy.eat();
}
Can be seen, Java
the agency is very simple, but the bottom is how to achieve it?
Referring to elaborate JDK dynamic proxy implementation principle , we main
set about the JVM
property
public static void main(String[] args) {
//将生成的代理类文件保存
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
Student student = new Student();
StudentInvokeHandler studentInvokeHandler = new StudentInvokeHandler(student);
People studentProxy = (People) Proxy.newProxyInstance(StudentInvokeHandler.class.getClassLoader(), new Class[]{People.class}, studentInvokeHandler);
studentProxy.eat();
}
After the run, the project can be found in the root directory of the com/sun/proxy/$Proxy0.class
file, which is the proxy Student
objects generated .class
files:
public final class $Proxy0 extends Proxy implements People {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void eat() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("com.dengchengchao.springtest.proxy.People").getMethod("eat");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
Through the above file we can find:
Generated proxy class inherits
Proxy
realizedPeople
interfacesThis is why
JDK
the proxy can only proxy interface, not proxy the specific class, becauseJava
not multiple inheritance, it can only implement the interfaceBecause the interface is achieved, thus generating a proxy object for
proxy
proxy instanceof People //true proxy instanceof Student //false
This is the beginning of the root cause of the problems we encountered, proxy
just to achieve the People
interface is not inherited from Student
class, so you can not proxy
object to a Student
type, it was reported fault.
Understand the problem, the underlying future use as JDK
a proxy class, it will not make another mistake.
If you thought that it was good, welcome to scan the following QR code concern micro-channel public number: Yat tour Java, from time to time publish articles related to Java advanced every day, thanks to attention