Apache Pool 2添加对象时出现Class Cast Exception问题排查
这个问题其实不是Employee对象本身需要大改,而是你对Apache Pool 2的核心机制理解有点偏差——池中的对象必须被PooledObject包装后才能被管理,直接把Employee实例丢进池里肯定会触发类型转换异常。
下面是具体的调整方案,其中涉及Employee的修改只有可选的增强部分,核心是修正工厂类的实现:
1. 核心修正:确保工厂返回包装后的PooledObject
你的EmployeeObjectFactory继承了PooledObjectFactory,但一定要注意makeObject()方法的返回值必须是PooledObject<Employee>,而非直接返回Employee。Apache Pool 2提供了DefaultPooledObject作为默认的包装类,你只需要在工厂里用它把Employee包起来就行:
import org.apache.commons.pool2.PooledObject; import org.apache.commons.pool2.PooledObjectFactory; import org.apache.commons.pool2.impl.DefaultPooledObject; public class EmployeeObjectFactory implements PooledObjectFactory<Employee> { @Override public PooledObject<Employee> makeObject() throws Exception { // 创建Employee实例,这里可以换成你的初始化逻辑 Employee emp = new Employee("John", "Doe", "EMP123", 30); // 用DefaultPooledObject包装后返回 return new DefaultPooledObject<>(emp); } // 其他方法(destroyObject, validateObject, activateObject, passivateObject)按需实现 @Override public void destroyObject(PooledObject<Employee> p) throws Exception { // 清理资源逻辑,比如关闭Employee关联的资源(如果有的话) } @Override public boolean validateObject(PooledObject<Employee> p) { // 验证对象是否可用的逻辑,比如检查employeeId是否为空 return p.getObject().getEmployeeId() != null; } @Override public void activateObject(PooledObject<Employee> p) throws Exception { // 激活对象的逻辑,比如重置临时状态 } @Override public void passivateObject(PooledObject<Employee> p) throws Exception { // 钝化对象的逻辑,比如清空临时数据 } }
2. Employee对象的可选增强(非必须,但推荐)
如果需要让池更好地跟踪对象的使用情况,你可以让Employee实现org.apache.commons.pool2.TrackedUse接口,这个接口只有一个getLastUsed()方法,用来记录对象最后被使用的时间:
import org.apache.commons.pool2.TrackedUse; import java.util.Date; public class Employee implements TrackedUse { private String firstName; private String lastName; private String employeeId; private int age; private Date lastUsed; // 构造函数、getter/setter省略 @Override public long getLastUsed() { return lastUsed != null ? lastUsed.getTime() : 0; } // 可以在对象被借出时更新lastUsed,比如在工厂的activateObject里调用,或者在业务逻辑中设置 public void setLastUsed(Date lastUsed) { this.lastUsed = lastUsed; } }
这个修改是可选的,如果你不需要跟踪使用时间,完全可以保持Employee原来的样子。
3. 主类中正确使用池的方式
最后,在主类里不要直接往池里添加Employee实例,而是通过池的addObject()方法让工厂来创建并包装对象,或者用borrowObject()直接获取可用对象:
import org.apache.commons.pool2.impl.GenericObjectPool; import org.apache.commons.pool2.impl.GenericObjectPoolConfig; public class Main { public static void main(String[] args) throws Exception { GenericObjectPoolConfig<Employee> poolConfig = new GenericObjectPoolConfig<>(); poolConfig.setMaxTotal(10); // 设置池的最大容量 EmployeeObjectFactory factory = new EmployeeObjectFactory(); GenericObjectPool<Employee> employeePool = new GenericObjectPool<>(factory, poolConfig); // 方式1:通过addObject让工厂创建并添加包装后的对象到池里 employeePool.addObject(); // 方式2:直接借出对象,池会自动创建(如果没有可用对象且未达上限) Employee emp = employeePool.borrowObject(); System.out.println("Borrowed employee: " + emp.getFirstName()); // 使用完后归还对象 employeePool.returnObject(emp); // 关闭池 employeePool.close(); } }
总结一下:Employee本身不需要强制修改,核心是让你的工厂正确返回PooledObject<Employee>(用DefaultPooledObject包装),然后通过池的标准方法来管理对象,而不是直接操作原始的Employee实例。
内容的提问来源于stack exchange,提问作者Vinnie

