可结合这个博客看
https://blog.csdn.net/riemann_/article/details/118500805、https://cloud.tencent.com/developer/article/1409315、https://blog.csdn.net/qq_43631716/article/details/120239438
本篇内容借鉴于chatgtp,应该有错误,仅作方法应用的参考,如有错误,请指出
InstantiationAwareBeanPostProcessor类是什么作用?
该类继承于BeanPostProcessor,是 Spring Framework 中的一个接口,用于在 Spring 容器实例化 bean 实例过程中的各个阶段插入自定义的逻辑,提供了以下几个方法,可以让开发者在不同的 bean 实例化阶段进行干预:
applyBeanPostProcessorsBeforeInstantiation()方法的作用
这个方法的主要目的是在 bean 实例化之前允许开发者进行干预,例如返回不同的实例、应用代理等。它提供了一种高度的灵活性,可以用于一些特定的定制和场景,如实现懒加载、实现某种特定的单例模式、应用一些自定义的实例化逻辑等。
需要注意的是,使用 applyBeanPostProcessorsBeforeInstantiation 方法需要谨慎,因为它可以完全替代默认的实例化过程,可能会引入复杂性和不可预测的行为。在大多数情况下,通常不需要直接使用这个方法,而是通过其他 Spring 提供的功能来实现所需的定制。
postProcessBeforeInstantiation()方法的作用?
postProcessBeforeInstantiation 是 Spring Framework 中的一个回调方法,属于 InstantiationAwareBeanPostProcessor 接口的一部分。它在 Spring 容器实例化 bean 之前被调用,允许您在实例化过程中插入自定义的逻辑。这个方法的主要用途在于,您可以在 bean 实例化之前对要实例化的类类型进行检查或者在特定条件下返回一个不同的实例。这为您提供了在实例化 bean 之前进行一些特殊处理的机会,如返回代理对象、缓存对象、应用不同的子类等。
举个例子
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
public class CustomInstantiationProcessor extends InstantiationAwareBeanPostProcessorAdapter {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
if (beanClass == MyBean.class && "myBeanName".equals(beanName)) {
// Return a custom instance of MyBean
return new CustomMyBean(); // You can return any instance you want
}
return null; // Proceed with regular instantiation
}
}
在上面的示例中,我们实现了一个自定义的 InstantiationAwareBeanPostProcessor,并重写了 postProcessBeforeInstantiation 方法。在这个方法中,我们检查要实例化的类是否是 MyBean,并且要创建的 bean 的名称是否为 “myBeanName”。如果条件匹配,我们返回一个自定义的 CustomMyBean 实例,从而在实例化之前进行了定制。需要注意的是,如果您返回了非空实例,Spring 将跳过默认的实例化过程,直接使用您返回的实例。如果返回 null,则 Spring 将继续执行默认的实例化逻辑。这个方法可以用于各种场景,例如根据不同的条件返回不同的实例,进行实例的代理或者装饰,或者进行实例的预处理。但是,要小心不要滥用这个功能,以免造成复杂性和不可预测的行为。
再比如返回代理对象,举个例子
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyInstantiationProcessor extends InstantiationAwareBeanPostProcessorAdapter {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) {
if (beanClass == UserServiceImpl.class) {
return createProxy(UserServiceImpl.class);
}
return null; // Proceed with regular instantiation
}
private Object createProxy(Class<?> targetClass) {
return Proxy.newProxyInstance(
targetClass.getClassLoader(),
new Class[]{UserService.class},
new PermissionCheckingHandler(new UserServiceImpl())
);
}
private static class PermissionCheckingHandler implements InvocationHandler {
private final UserService target;
public PermissionCheckingHandler(UserService target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// Perform permission checking logic here
if (checkPermission()) {
return method.invoke(target, args);
} else {
throw new SecurityException("Permission denied");
}
}
private boolean checkPermission() {
// Check permission logic
return true; // For demonstration purposes
}
}
}
在这个示例中,我们实现了一个自定义的 InstantiationAwareBeanPostProcessor,并postProcessBeforeInstantiation 方法中返回了一个代理对象。代理对象使用 JDK 动态代理,代理了 UserServiceImpl 类,同时实现了 UserService 接口。代理对象的 invoke 方法中执行了权限检查,然后根据结果决定是否调用实际的方法。这种方法允许您在实例化 bean 之前对其进行定制,包括创建代理对象以实现横切关注点,如权限检查、日志记录等。请注意,这只是一个简化的示例,实际情况可能会更加复杂。
BeanPostProcessorsAfterInstantiation()方法的作用
和BeanPostProcessorsBeforeInstantiation()方法差不多,只不过是在实例化之后,属性注入之前进行的操作。
postProcessProperties()法的作用
让我们考虑一个示例:一个简单的权限管理系统中的用户对象。我们将在该方法中进行权限验证和动态注入属性。假设我们有一个用户类 User,其中包含用户的基本信息和角色信息。我们想要在初始化用户对象之前,根据用户角色动态注入不同的权限。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.stereotype.Component;
@Component
public class PermissionInjector implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
return true;
}
@Override
public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
if (bean instanceof User) {
User user = (User) bean;
// 根据用户角色注入不同的权限
if (user.getRole().equals("ADMIN")) {
user.setPermissions("ALL_PERMISSIONS");
} else if (user.getRole().equals("USER")) {
user.setPermissions("READ_PERMISSION");
}
}
return pvs;
}
}
这个示例中,我们创建了一个名为 PermissionInjector 的类,实现了 InstantiationAwareBeanPostProcessor 接口。在 postProcessProperties() 方法中,我们检查了 Bean 是否为 User 类型,如果是,根据用户角色注入不同的权限。例如,如果用户角色是 “ADMIN”,则注入所有权限;如果用户角色是 “USER”,则只注入读取权限。
需要注意的是,postProcessProperties() 方法的返回值是 PropertyValues 对象,您可以对其进行修改,以修改属性的值。在此示例中,我们没有修改 PropertyValues,因此返回原始的值。
最后,在使用 Spring 容器创建和初始化 User 对象时,PermissionInjector 中的 postProcessProperties() 方法会被自动调用,根据用户角色注入不同的权限。
postProcessPropertyValues()方法的作用
postProcessPropertyValues 是 InstantiationAwareBeanPostProcessor 接口中的一个方法,用于在 Spring 容器进行属性注入之前对属性进行自定义操作。这个方法在 bean 的属性注入之前被调用,允许您修改、替换或添加属性的值
import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
public class CustomPropertyProcessor extends InstantiationAwareBeanPostProcessorAdapter {
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
if (bean instanceof User && "userBean".equals(beanName)) {
// Customize property values before injection
MutablePropertyValues newPropertyValues = new MutablePropertyValues(pvs);
PropertyValue usernameValue = newPropertyValues.getPropertyValue("username");
if (usernameValue != null) {
String username = (String) usernameValue.getValue();
newPropertyValues.add("username", username.toUpperCase());
}
newPropertyValues.add("additionalProperty", "customValue");
return newPropertyValues;
}
return pvs;
}
}
在上面的示例中,CustomPropertyProcessor 类实现了 InstantiationAwareBeanPostProcessor 接口,并重写了 postProcessPropertyValues 方法。在这个方法中,我们检查要处理的 bean 是否是 User 类型,并且要处理的 bean 的名称是否为 “userBean”。如果条件匹配,我们使用 MutablePropertyValues 创建一个新的属性值集合,然后修改了 username 属性的值为大写字母,并添加了一个名为 additionalProperty 的额外属性。
这种方法允许您在属性注入之前对属性进行定制,以满足特定的需求。
populateBean()方法的作用
populateBean 方法是 Spring Framework 中的一个核心方法,用于将属性值填充到已实例化的 bean 实例中,完成属性的注入。它属于 AbstractAutowireCapableBeanFactory 类,是 Spring 容器中实现属性注入的重要部分。populateBean 方法用于将属性值填充到 bean 实例中,完成属性的注入。在 Spring 容器创建 bean 的过程中,当 bean 实例化完成后,它需要进行属性注入,以便将依赖关系和配置值传递给 bean。
执行过程:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory {
// ...
protected void populateBean(String beanName, RootBeanDefinition mbd, BeanWrapper bw) {
PropertyValues pvs = mbd.getPropertyValues();
for (PropertyValue pv : pvs.getPropertyValues()) {
String propertyName = pv.getName();
Object originalValue = pv.getValue();
Object convertedValue = getConvertedValue(originalValue, bw.getPropertyDescriptor(propertyName));
bw.setPropertyValue(propertyName, convertedValue);
}
}
private Object getConvertedValue(Object originalValue, PropertyDescriptor pd) {
// Perform type conversion or other transformations if needed
// Return the converted value
}
}
在上面的示例中,populateBean 方法使用 PropertyValues 来获取要填充到 bean 实例中的属性值集合。然后,它使用 BeanWrapper 包装 bean 实例,通过遍历属性值集合,将属性值填充到 bean 实例中。在填充过程中,可能会进行属性编辑器转换或类型转换,以确保属性值的兼容性。populateBean 方法是 Spring 容器中用于属性注入的关键方法,它确保在 bean 创建过程中,将配置的属性值正确地填充到 bean 实例中,以满足依赖关系和定制需求。
postProcessBeforeInitialization()方法的作用
postProcessBeforeInitialization 是 Spring Framework 中的一个方法,属于 BeanPostProcessor 接口的一部分。它在 bean 初始化方法执行之前被调用,允许您在 bean 初始化之前应用自定义的逻辑。
方法的调用过程:
示例:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class CustomBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof MyBean) {
// Apply custom logic before initialization
((MyBean) bean).doSomethingBeforeInitialization();
}
return bean; // Continue with the original bean instance
}
}
在上面的示例中,我们实现了一个自定义的 BeanPostProcessor,并重写了 postProcessBeforeInitialization 方法。在这个方法中,我们检查要处理的 bean 是否是 MyBean 类型,如果是的话,我们调用了 doSomethingBeforeInitialization 方法,以应用自定义的逻辑。然后,我们返回原始的 bean 实例,以继续后续的初始化过程。需要注意的是,postProcessBeforeInitialization 方法主要用于在 bean 初始化之前应用定制逻辑。如果您需要在 bean 初始化之后应用处理逻辑,可以使用 postProcessAfterInitialization 方法。
Aware接口的理解(标记作用)
ApplicationContextAwareProcessor#postProcessBeforeInitialization 首先判断此 bean 是不是各种的Aware,如果是它列举的那几个 Aware 就获取 Bean 工厂的权限,可以向容器中导入相关的上下文环境,目的是为了 Bean 实例能够获取到相关的上下文,如果不是它列举的几个 Aware,那就调invokeAwareInterfaces(bean),向容器中添加相关接口的上下文环境。
在 Spring 框架中的 bean 初始化过程中的一个步骤,具体来说是在 bean 初始化前的处理阶段,方法名为 postProcessBeforeInitialization。这个方法是在 Bean 初始化之前调用的一个扩展点,允许开发者在 Bean 初始化之前进行一些自定义的处理。在这个方法中,首先会判断当前的 Bean 是否实现了 Spring 的一些特定接口,比如 Aware 接口,这些接口包括 BeanFactoryAware、ApplicationContextAware 等。如果 Bean 实现了这些接口,它就会获得与容器相关的权限,可以获取到 Bean 工厂或者应用上下文,从而能够与容器进行交互。这些 Aware 接口的目的是为了让 Bean 能够获得它所在的上下文环境,以便进行一些操作或者获取一些资源。
如果 Bean 没有实现上述的 Aware 接口,那么在 postProcessBeforeInitialization 方法中会调用 invokeAwareInterfaces(bean),该方法会向容器中添加相关接口的上下文环境。这个步骤的目的是为了让 Bean 也能够通过接口方式获取到一些上下文环境。主要是 Spring 框架在 Bean 初始化前的一系列处理,主要是为了让 Bean 能够获得与容器相关的上下文环境,以便进行后续的操作。这是 Spring 框架中的一个重要的生命周期阶段,允许开发者在此阶段进行一些自定义的操作。
举个例子:
当你在使用 Spring 框架创建一个自定义的 Bean 时,你可能会需要在 Bean 初始化前获取到一些与容器相关的上下文环境。这时,你可以通过实现特定的 Aware 接口或者在 postProcessBeforeInitialization 方法中添加相应的逻辑来实现。举一个例子,假设你有一个名为 UserService 的 Bean,它需要在初始化前获取到应用程序上下文(ApplicationContext),以便在后续的操作中使用。你可以按照以下步骤实现:
public class UserService {
private ApplicationContext applicationContext;
// 在这里定义其他属性和方法
public void doSomething() {
// 在这里使用 applicationContext 进行操作
// ...
}
}
让 UserService 类实现 ApplicationContextAware 接口,并实现接口中的方法,这样你就能够获取到应用程序上下文。
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class UserService implements ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) {
this.applicationContext = applicationContext;
}
// 在这里定义其他属性和方法
public void doSomething() {
// 在这里使用 applicationContext 进行操作
// ...
}
}
在 UserService 类中,你可以在 doSomething 方法中使用 applicationContext 来获取一些上下文信息或者执行一些操作。
public void doSomething() {
// 在这里使用 applicationContext 进行操作
SomeOtherBean someOtherBean = applicationContext.getBean(SomeOtherBean.class);
// 执行操作...
}
当 Spring 容器初始化 UserService Bean 时,由于 UserService 实现了 ApplicationContextAware 接口,Spring 会自动调用 setApplicationContext 方法,并将应用程序上下文传递给 UserService 对象。这样,在 doSomething 方法中就可以使用应用程序上下文来获取其他 Bean,执行一些操作,或者获取其他上下文信息。通过这个例子,你可以更好地理解在 Spring 中如何利用 Aware 接口和 postProcessBeforeInitialization 方法来获取与容器相关的上下文环境,以及如何在 Bean 初始化前进行自定义处理。
InitializingBean.afterPropertiesSet()
InitializingBean 是 Spring Framework 中的一个接口,用于在 Bean 初始化过程中执行特定的操作。它定义了一个方法 afterPropertiesSet(),在 Spring 容器创建 Bean 并设置了所有属性后,会自动调用该方法,允许开发者在此方法中执行自定义的初始化逻辑。当一个 Bean 实现了 InitializingBean 接口并且定义了 afterPropertiesSet() 方法时,Spring 容器会在以下情况下自动调用该方法:
当使用 InitializingBean 接口的 afterPropertiesSet() 方法时,让我们考虑一个简单的示例:一个订单处理系统中的订单对象。我们将在 afterPropertiesSet() 方法中进行属性验证和初始化。
import org.springframework.beans.factory.InitializingBean;
public class Order implements InitializingBean {
private String orderId;
private double amount;
public String getOrderId() {
return orderId;
}
public void setOrderId(String orderId) {
this.orderId = orderId;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
@Override
public void afterPropertiesSet() throws Exception {
// 在属性设置后执行初始化逻辑
if (orderId == null || orderId.isEmpty()) {
throw new IllegalArgumentException("Order ID cannot be null or empty.");
}
if (amount <= 0) {
throw new IllegalArgumentException("Order amount must be greater than 0.");
}
// 执行其他初始化操作
System.out.println("Order initialized: ID = " + orderId + ", Amount = " + amount);
}
}
在这个示例中,Order 类实现了 InitializingBean 接口,并在 afterPropertiesSet() 方法中进行了属性验证和初始化操作。如果订单的ID为空或金额小于等于0,则会抛出异常。然后,在方法的最后,我们输出初始化的订单信息。
在使用该订单对象时,Spring 容器会在属性设置之后自动调用 afterPropertiesSet() 方法,以确保订单在被使用之前已经通过了验证并且具备正确的初始化状态。
postProcessAfterInitialization()方法
postProcessAfterInitialization 是 Spring 框架中一个用于扩展的回调方法,用于在 Bean 初始化之后执行自定义的逻辑。这个方法允许开发者在 Bean 初始化完成后对 Bean 进行进一步的处理或者添加自定义逻辑。
在 Spring 容器初始化 Bean 的过程中,postProcessAfterInitialization 方法会在每个 Bean 初始化完成后被调用,允许你在 Bean 初始化之后执行一些额外的操作。
举个例子,假设你有一个名为 LoggingService 的 Bean,你希望在它初始化完成后打印一条日志。你可以创建一个实现了 BeanPostProcessor 接口的类,然后在 postProcessAfterInitialization 方法中添加日志记录逻辑。
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class LoggingBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// 在 Bean 初始化完成后添加日志记录逻辑
System.out.println("Bean '" + beanName + "' has been initialized.");
return bean;
}
}
然后,在 Spring 配置文件中,将这个自定义的 LoggingBeanPostProcessor 注册为一个 Bean:
<bean class="com.example.LoggingBeanPostProcessor" />
现在,每当 Spring 容器初始化一个 Bean 时,postProcessAfterInitialization 方法会被调用,并且你的日志记录逻辑会在每个 Bean 初始化完成后执行。
需要注意的是,postProcessAfterInitialization 方法的返回值通常是传入的 bean 参数本身,但你也可以对其进行修改(例如,包装成代理对象等),然后返回修改后的对象。
总之,postProcessAfterInitialization 方法允许你在 Spring 容器初始化 Bean 后执行自定义的逻辑,可以用于实现诸如日志记录、代理创建、监控等功能。
补充:PropertyValues类是什么
在 Spring Framework 中,pvs 是一个代表属性的容器,全称为 PropertyValues。它用于存储一个 bean 实例的属性及其对应的值,可以在属性注入过程中进行访问和操作。
PropertyValues 对象包含了一组 PropertyValue 对象,每个 PropertyValue 对象表示一个属性及其对应的值。属性的名称由字符串表示,属性的值可以是任何类型的对象。
在 Spring 的属性注入过程中,PropertyValues 会被用于存储要注入到 bean 实例中的属性值,以及可能在注入之前或之后进行修改的机会。
以下是一个简单示例,演示如何创建一个 PropertyValues 对象并添加属性值:
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
// 创建一个 MutablePropertyValues 对象
MutablePropertyValues propertyValues = new MutablePropertyValues();
// 添加属性及其对应的值
propertyValues.add("username", "john_doe");
propertyValues.add("email", "[email protected]");
// 获取属性值
PropertyValue usernameValue = propertyValues.getPropertyValue("username");
String username = (String) usernameValue.getValue();
PropertyValue emailValue = propertyValues.getPropertyValue("email");
String email = (String) emailValue.getValue();
在 Spring 容器创建 bean 的过程中,PropertyValues 对象会被传递给 BeanFactory 或 ApplicationContext 中的相应实现,以完成属性的注入。在使用 InstantiationAwareBeanPostProcessor 接口的 postProcessPropertyValues 方法时,您可以获取并操作这个 PropertyValues 对象,以实现自定义的属性处理逻辑。
补充:MutablePropertyValues类是什么
MutablePropertyValues 是 Spring Framework 中的一个类,用于表示可变的属性值集合。它实现了 PropertyValues 接口,提供了一种方便的方式来管理属性及其对应的值,可以用于在 Spring 容器中进行属性的设置和修改。
通过 MutablePropertyValues,您可以创建一个属性值集合,然后逐个添加、修改或删除属性及其对应的值。这在处理属性注入、属性值定制以及一些自定义逻辑方面非常有用。
import org.springframework.beans.MutablePropertyValues;
import org.springframework.beans.PropertyValue;
// 创建一个 MutablePropertyValues 对象
MutablePropertyValues propertyValues = new MutablePropertyValues();
// 添加属性及其对应的值
propertyValues.add("username", "john_doe");
propertyValues.add("email", "[email protected]");
// 获取属性值
PropertyValue usernameValue = propertyValues.getPropertyValue("username");
String username = (String) usernameValue.getValue();
PropertyValue emailValue = propertyValues.getPropertyValue("email");
String email = (String) emailValue.getValue();
// 修改属性值
propertyValues.add("email", "[email protected]");
// 删除属性
propertyValues.removePropertyValue("username");
// 判断是否包含某个属性
boolean containsEmail = propertyValues.contains("email");
// 获取所有属性的名称
String[] propertyNames = propertyValues.getPropertyNames();
MutablePropertyValues 可以在多个场景中使用,包括在 InstantiationAwareBeanPostProcessor 的 postProcessPropertyValues 方法中,以及在手动创建和配置 bean 的过程中。它为属性值的设置和修改提供了一种灵活且可操作的方式。