一、核心概念对比
1.1 一句话总结
BeanFactory是Spring的"工厂总管",FactoryBean是"特殊产品生产线"
1.2 详细对比表
| 维度 | BeanFactory | FactoryBean |
|---|---|---|
| 定位 | Spring IoC容器的核心接口 | 创建复杂Bean的扩展接口 |
| 职责 | 管理所有Bean的生命周期 | 专门生产特定类型的复杂Bean |
| 方法数量 | 20+个方法(getBean、containsBean等) | 3个核心方法(getObject、getObjectType、isSingleton) |
| 实现者 | ApplicationContext、DefaultListableBeanFactory | MyBatis的SqlSessionFactoryBean、Spring的ProxyFactoryBean |
| 使用场景 | 所有Bean的获取和管理 | 需要复杂创建逻辑的对象(如动态代理) |
二、源码级解析
2.1 BeanFactory接口结构
java
复制
下载
public interface BeanFactory {
// 核心方法:获取Bean
Object getBean(String name) throws BeansException;
// 检查是否包含Bean
boolean containsBean(String name);
// 是否是单例
boolean isSingleton(String name) throws NoSuchBeanDefinitionException;
// 获取Bean类型
Class<?> getType(String name) throws NoSuchBeanDefinitionException;
// 还有20+个其他方法...
}
2.2 FactoryBean接口结构
java
复制
下载
public interface FactoryBean<T> {
// 核心:创建对象的方法
T getObject() throws Exception;
// 返回对象的类型
Class<?> getObjectType();
// 是否单例
boolean isSingleton();
}
三、动态代理生成的实战案例
3.1 FactoryBean实现动态代理
java
复制
下载
/**
* 动态代理FactoryBean示例:为任意接口生成代理
*/
@Component
public class DynamicProxyFactoryBean implements FactoryBean<Object>, InitializingBean {
private Class<?> targetInterface; // 要代理的接口
private Object targetObject; // 真实对象(可选)
private Object proxy; // 代理对象
/**
* 核心方法:创建代理对象
*/
@Override
public Object getObject() throws Exception {
if (proxy == null) {
proxy = createProxy();
}
return proxy;
}
/**
* 创建JDK动态代理
*/
private Object createProxy() {
return Proxy.newProxyInstance(
targetInterface.getClassLoader(),
new Class[]{targetInterface},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强:记录日志
logBefore(method, args);
// 方法执行
Object result;
long startTime = System.currentTimeMillis();
try {
if (targetObject != null) {
// 调用真实对象的方法
result = method.invoke(targetObject, args);
} else {
// 无真实对象的情况(如MyBatis Mapper)
result = handleMethodWithoutTarget(method, args);
}
// 后置增强:记录结果
logAfter(method, result, System.currentTimeMillis() - startTime);
return result;
} catch (InvocationTargetException e) {
// 异常增强
handleException(method, e.getTargetException());
throw e.getTargetException();
}
}
}
);
}
/**
* 记录方法调用日志
*/
private void logBefore(Method method, Object[] args) {
System.out.println("[" + new Date() + "] 调用方法: " + method.getName());
if (args != null && args.length > 0) {
System.out.println("参数: " + Arrays.toString(args));
}
}
/**
* 处理无实现类的方法调用(如MyBatis Mapper)
*/
private Object handleMethodWithoutTarget(Method method, Object[] args) {
String methodName = method.getName();
// 这里可以根据方法名、参数等信息执行相应逻辑
// 比如:转换SQL语句、调用远程服务等
System.out.println("处理方法调用: " + methodName);
// 返回默认值(实际项目中会有具体实现)
if (method.getReturnType() == void.class) {
return null;
} else if (method.getReturnType() == String.class) {
return "proxy-result";
} else if (method.getReturnType() == List.class) {
return Collections.emptyList();
} else if (method.getReturnType().isPrimitive()) {
return 0;
}
return null;
}
@Override
public Class<?> getObjectType() {
return targetInterface;
}
@Override
public boolean isSingleton() {
return true; // 代理对象通常是单例
}
@Override
public void afterPropertiesSet() throws Exception {
// 参数验证
Assert.notNull(targetInterface, "目标接口不能为空");
Assert.isTrue(targetInterface.isInterface(), "目标必须是接口");
}
// Getter和Setter
public void setTargetInterface(Class<?> targetInterface) {
this.targetInterface = targetInterface;
}
public void setTargetObject(Object targetObject) {
this.targetObject = targetObject;
}
}
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc
需要全套面试笔记及答案
【点击此处即可/免费获取】
3.2 使用CGLIB创建类代理
java
复制
下载
/**
* CGLIB代理FactoryBean:可以为类创建代理(不需要接口)
*/
@Component
public class CglibProxyFactoryBean implements FactoryBean<Object> {
private Class<?> targetClass;
private Object target;
private Object proxy;
@Override
public Object getObject() throws Exception {
if (proxy == null) {
proxy = createCglibProxy();
}
return proxy;
}
/**
* 使用CGLIB创建代理
*/
private Object createCglibProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args,
MethodProxy proxy) throws Throwable {
// 方法过滤:不代理Object类的方法
if (method.getDeclaringClass() == Object.class) {
return proxy.invokeSuper(obj, args);
}
// 前置增强
System.out.println("CGLIB代理 - 调用前: " + method.getName());
// 执行原方法
long start = System.currentTimeMillis();
Object result = proxy.invokeSuper(obj, args);
// 后置增强
System.out.println("CGLIB代理 - 调用后: " + method.getName() +
", 耗时: " + (System.currentTimeMillis() - start) + "ms");
return result;
}
});
return enhancer.create();
}
@Override
public Class<?> getObjectType() {
return targetClass;
}
@Override
public boolean isSingleton() {
return true;
}
}
3.3 XML配置示例
xml
复制
下载
运行
<!-- 配置FactoryBean -->
<bean id="userServiceProxy" class="com.example.DynamicProxyFactoryBean">
<property name="targetInterface" value="com.example.UserService"/>
<property name="targetObject" ref="userServiceImpl"/>
</bean>
<bean id="productDaoProxy" class="com.example.CglibProxyFactoryBean">
<property name="targetClass" value="com.example.ProductDao"/>
</bean>
3.4 注解配置示例
java
复制
下载
@Configuration
public class ProxyConfig {
@Bean
public FactoryBean<Object> userMapperProxy() {
DynamicProxyFactoryBean factoryBean = new DynamicProxyFactoryBean();
factoryBean.setTargetInterface(UserMapper.class);
// 可以设置自定义的InvocationHandler
return factoryBean;
}
@Bean
public UserService userServiceProxy(@Autowired UserServiceImpl userService) {
// 或者使用@Bean方法直接返回代理
return (UserService) Proxy.newProxyInstance(
UserService.class.getClassLoader(),
new Class[]{UserService.class},
new UserServiceInvocationHandler(userService)
);
}
}
四、实际框架中的应用
4.1 MyBatis的MapperFactoryBean
java
复制
下载
/**
* MyBatis MapperFactoryBean的简化版实现
*/
public class MyBatisMapperFactoryBean<T> implements FactoryBean<T> {
private SqlSession sqlSession;
private Class<T> mapperInterface;
@Override
public T getObject() throws Exception {
// MyBatis的核心:为接口创建动态代理
return sqlSession.getMapper(mapperInterface);
}
@Override
public Class<?> getObjectType() {
return mapperInterface;
}
@Override
public boolean isSingleton() {
return true;
}
}
4.2 Spring AOP的ProxyFactoryBean
java
复制
下载
/**
* Spring早期AOP的ProxyFactoryBean
*/
public class AopProxyFactoryBean implements FactoryBean<Object>, BeanClassLoaderAware {
private Object target;
private Advisor advisor;
@Override
public Object getObject() throws Exception {
// 创建AOP代理
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvisor(advisor);
// 根据情况选择JDK代理或CGLIB代理
if (target.getClass().getInterfaces().length > 0) {
proxyFactory.setInterfaces(target.getClass().getInterfaces());
return proxyFactory.getProxy();
} else {
return proxyFactory.getProxy(target.getClass().getClassLoader());
}
}
}
4.3 缓存代理FactoryBean
java
复制
下载
/**
* 带缓存功能的代理FactoryBean
*/
@Component
public class CacheableProxyFactoryBean implements FactoryBean<Object> {
private Object target;
private Map<String, Object> cache = new ConcurrentHashMap<>();
@Override
public Object getObject() throws Exception {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 检查是否有@Cacheable注解
if (method.isAnnotationPresent(Cacheable.class)) {
String cacheKey = generateCacheKey(method, args);
// 从缓存获取
if (cache.containsKey(cacheKey)) {
System.out.println("缓存命中: " + cacheKey);
return cache.get(cacheKey);
}
// 执行方法
Object result = method.invoke(target, args);
// 存入缓存
cache.put(cacheKey, result);
System.out.println("缓存写入: " + cacheKey);
return result;
}
// 没有缓存注解,直接执行
return method.invoke(target, args);
}
private String generateCacheKey(Method method, Object[] args) {
StringBuilder key = new StringBuilder(method.getName());
if (args != null) {
for (Object arg : args) {
key.append(":").append(arg);
}
}
return key.toString();
}
}
);
}
}
五、面试回答要点
5.1 回答结构
第一层:概念区别
-
BeanFactory:Spring容器核心,管理所有Bean
-
FactoryBean:创建复杂对象的工厂,本身也是一个Bean
第二层:设计目的
-
分离关注点:BeanFactory负责通用逻辑,FactoryBean负责特殊创建
-
开闭原则:通过扩展而不是修改来增加功能
第三层:动态代理实战
-
FactoryBean的getObject()方法是创建代理的最佳位置
-
可以封装JDK Proxy、CGLIB等代理创建逻辑
-
在代理中可以加入日志、缓存、事务等横切关注点
篇幅限制下面就只能给大家展示小册部分内容了。整理了一份核心面试笔记包括了:Java面试、Spring、JVM、MyBatis、Redis、MySQL、并发编程、微服务、Linux、Springboot、SpringCloud、MQ、Kafc
需要全套面试笔记及答案
【点击此处即可/免费获取】
5.2 高频问题应对
Q:什么时候用FactoryBean?
A:三种典型场景:
-
对象创建过程复杂(如需要多步初始化)
-
需要动态生成对象(如动态代理)
-
对象需要根据配置变化(如不同环境的配置)
Q:FactoryBean和@Bean方法选哪个?
A:
-
简单对象:用@Bean
-
复杂创建逻辑:用FactoryBean
-
需要复用创建逻辑:用FactoryBean
Q:如何获取FactoryBean本身?
A:使用"&"前缀:
java
复制
下载
// 获取产品
MyProduct product = context.getBean("myFactoryBean");
// 获取工厂本身
MyFactoryBean factory = context.getBean("&myFactoryBean");
六、性能优化建议
6.1 代理对象缓存
java
复制
下载
public class CachedProxyFactoryBean implements FactoryBean<Object> {
private volatile Object proxy; // volatile保证可见性
@Override
public Object getObject() throws Exception {
if (proxy == null) {
synchronized (this) {
if (proxy == null) { // 双重检查锁
proxy = createProxy();
}
}
}
return proxy;
}
}
6.2 懒加载支持
java
复制
下载
@Component
@Lazy // 配合@Lazy实现懒加载
public class LazyInitProxyFactoryBean implements FactoryBean<Object>, SmartFactoryBean<Object> {
@Override
public boolean isEagerInit() {
return false; // 不是急切初始化
}
@Override
public Object getObject() throws Exception {
// 第一次调用时才会创建代理
return createProxy();
}
}
七、总结
FactoryBean是Spring框架中一个强大的扩展点,特别适合:
-
动态代理生成:封装代理创建逻辑
-
复杂对象创建:多步骤初始化过程
-
资源池管理:如数据库连接池、线程池
-
协议适配:如RPC客户端、消息队列消费者
关键要点:
-
FactoryBean本身也是Bean,由BeanFactory管理
-
getObject()方法返回的是"产品",不是工厂本身
-
动态代理是FactoryBean最经典的应用场景
-
理解这个设计有助于掌握Spring的扩展机制