这是在使用Java的动态代理的时候遇到的一个错,它一直报类型转换异常。
这是代码:
接口类
public interface UserMapper {
int addUser(User user);
int deleteUser(int id);
int updateUser(User user);
List<User> userList();
}
接口实现类
package com.huchuan.mapper;
import com.huchuan.pojo.User;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @Author 胡川
* @Date 2021年07月08日 21:49
*/
@Repository
public class UserMapperImpl implements UserMapper{
@Override
public int addUser(User user) {
System.out.println("增加了一个用户!");
return 0;
}
@Override
public int deleteUser(int id) {
System.out.println("删除了一个用户!");
return 0;
}
@Override
public int updateUser(User user) {
System.out.println("修改了一个用户!");
return 0;
}
@Override
public List<User> userList() {
System.out.println("查询了一个(多个)用户!");
return null;
}
}
动态代理类(实现了InvocationHandler接口,重写了其invoke()方法)
public class MyProxy implements InvocationHandler {
// 被代理的对象
private Object target;
public void setProxy(Object target) {
this.target = target;
}
/**
* 生成得到代理类
*/
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
/**
*处理代理的实例,就是在这个方法中做被代理类执行方法的增强。并返回结果
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 方法执行前,需要做的事情。比如打印日志等
System.out.println(method.getDeclaringClass().getName()+" 类的->"+method.getName()+"方法执行了!");
// 执行代理类的方法
Object invoke = method.invoke(target, args);
// 方法执行后
System.out.println(method.getDeclaringClass().getName()+" 类的->"+method.getName()+"方法完成了!");
return invoke;
}
}
出问题的测试类
@Test
public void test1(){
// 真实角色,即被代理类对象
UserMapperImpl userMapper =new UserMapperImpl();
// 代理角色,不存在。
MyProxy myProxy = new MyProxy();
myProxy.setProxy(userMapper);
UserMapperImpl proxy =(UserMapperImpl) myProxy.getProxy();
proxy.deleteUser(1);
}
错误点在于返回的应该是这个类的实现的接口。
改正方法一,将其强转为该类实现的接口。代码如下:
@Test
public void test1(){
// 真实角色,即被代理类对象
UserMapperImpl userMapper =new UserMapperImpl();
// 代理角色,不存在。
MyProxy myProxy = new MyProxy();
myProxy.setProxy(userMapper);
UserMapper proxy =(UserMapper) myProxy.getProxy();
proxy.deleteUser(1);
}
运行截图:
解释:因为Spring的AOP底层默认使用JDK的动态代理来做的,是处理接口的。返回的也是个接口。
解决方式二,不用改变原来的代码,只需要在把 proxy-target-class="true" 设置为true就可以了。
如果是在配置文件里配置的,那就在<aop:config proxy-target-class="true"> 这个标签里入就可以了。
如果是用的注解,那就在配置文件,开启AOP注解的地方设置。
原理是,Spring的AOP底层默认支持的是JDK的动态代理来实现的,将这个标签属性的值设置为true就声明使用CGLIB来做。一个处理的接口,一个处理的继承。
总结,还是使用官方默认的b吧。如果真有需求再改。