文章源自JAVA秀-https://www.javaxiu.com/19880.html
回顾:通过前面的章节的了解,我们又了解了BeanPostProcessor接口的基本使用。当我们想要在一个bean被创建好之后,开发者能有机会参与到这个bean的初始化过程的时候,我们只需要实现BeanPostProcessor接口,并在接口方法里面选择性的初始化自己的bean对象即可。本章我们将新学习一个接口,这个接口就是InstantiationAwareBeanPostProcessor接口。 文章源自JAVA秀-https://www.javaxiu.com/19880.html
文章源自JAVA秀-https://www.javaxiu.com/19880.html
1. InstantiationAwareBeanPostProcessor接口的基本介绍
一、实际上来说,对于一个bean的生命周期而言,有两个非常重要的过程:bean的实例化和bean的初始化。 实例化就是创建一个bean,而初始化是对已经创建好的bean进行初始化。
[1]bean的实例化有三种方式:xml配置后spring容器创建,@Service等注解后spring创建,实现FactoryBean接口后用户代码自己创建。
[2]bean的初始化有三种方式:配置init-method属性方式,实现InitializingBean接口方式,实现BeanPostProcessor接口方式。文章源自JAVA秀-https://www.javaxiu.com/19880.html
二、了解了上面的一些重要的概念之后,我们再来了解InstantiationAwareBeanPostProcessor接口就好理解了。
因为InstantiationAwareBeanPostProcessor接口是继承至BeanPostProcessor接口的,所以这个接口是对BeanPostProcessor接口的功能的扩展,BeanPostProcessor接口所有的功能他都有。那么问题是都扩展了哪些功能呢?就是扩展了postProcessBeforeInstantiation、postProcessAfterInstantiation、postProcessPropertyValues三个方法。下面我们重点介绍一下这三个方法:文章源自JAVA秀-https://www.javaxiu.com/19880.html
[1] postProcessBeforeInstantiation方法:调用本方法之前某个业务bean还未被创建,开发者是否需要自己创建这个bean(用法与FactoryBean接口有点类似)。如果开发者在该方法内放置如下代码,则spring启动过程中不会自己通过反射的方式创建这个bean,而是执行下面的代码创建一个bean。文章源自JAVA秀-https://www.javaxiu.com/19880.html
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
//如果bean类型是UserServiceImpl,则该bean由开发者自己的代码创建
if(beanClass.equals(UserServiceImpl.class)) {
UserService userService = new UserServiceImpl();
return userService;
}
return null;
}
一旦该bean由上面的自定义代码段创建,那么下面的[2],[3]就不会被调用了。spring框架这么处理的目的很简单,就是如果开发者需要自己实例化一个业务bean,那么就在这里将初始化的工作一并处理了,无需再其它方法里面去做实例化。如果运行过程中去掉上面的自定义代码段,那么下面的[2]一定会执行。文章源自JAVA秀-https://www.javaxiu.com/19880.html
[2] postProcessAfterInstantiation方法:调用本方法主要是spring创建某个业务bean之后,给开发者一个介入的机会进行自定义的一些业务处理。除此之外,返回值的true和false直接决定了[3]方法是否执行。文章源自JAVA秀-https://www.javaxiu.com/19880.html
[3] postProcessPropertyValues方法:如果[2]中的方法返回的是true,那么本方法就会被调用,开发者可以再此处初始化一些自己的属性。文章源自JAVA秀-https://www.javaxiu.com/19880.html
总的来说,这个接口的几个方法重点归为两组接口:postProcessBeforeInstantiation方法,postProcessAfterInstantiation方法是一组;postProcessBeforeInitialization方法和postProcessAfterInitialization方法是一组。第一组是spring在实例化某个bean之前和实例化某个bean之后,给开发者一个介入的机会,用于做某些自定义的业务处理;第二组是spring在初始化某个bean之前和初始化某个bean之后,给开发者一个介入的机会,用于做某些自定义的业务处理。注意前面的区别,第一组是实例化,第二组是初始化。文章源自JAVA秀-https://www.javaxiu.com/19880.html
2. InstantiationAwareBeanPostProcessor接口的基本使用
第一步:创建一个User类如下:文章源自JAVA秀-https://www.javaxiu.com/19880.html
@Data
@NoArgsConstructor
@ToString
@EqualsAndHashCode
public class User implements Serializable {
private static final long serialVersionUID = 4800166777883697833L;
private Long id;
private String name;
private String identity;
private String mobile;
private String bankcard;
private Integer age;
private Integer gender;
}
第二步:创建一个接口和接口实现类如下:文章源自JAVA秀-https://www.javaxiu.com/19880.html
public interface UserService {
User findUserById(Long id);
}
@Service
public class UserServiceImpl implements UserService {
public String ip;
public String port;
public String getIp() {
return ip;
}
public void setIp(String ip) {
this.ip = ip;
}
public String getPort() {
return port;
}
public void setPort(String port) {
this.port = port;
}
@Override
public User findUserById(Long id) {
User user = new User();
user.setId(id);
user.setName("张山");
user.setIdentity("张山");
user.setBankcard("36457736355363");
user.setMobile("16752652625");
user.setGender(2);
user.setAge(18);
System.out.println("ip: " + ip);
System.out.println("port: " + port);
return user;
}
}
第三步:创建一个实现InstantiationAwareBeanPostProcessor接口的实现类如下:文章源自JAVA秀-https://www.javaxiu.com/19880.html
@Component
public class GlobalInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
@Override
public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
//测试一:开发者自己实例化UserServiceImpl这个bean,不要让spring通过反射的方式创建。
if(beanClass.equals(UserServiceImpl.class)) {
UserService userService = new UserServiceImpl();
System.out.println("address1" + userService);
return userService;
}
return null;
}
@Override
public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
//测试二:spring通过反射的方式创建UserServiceImpl这个bean,然后返回一个true或者false。
//返回true的意思是告诉spring,需要调用下面的postProcessPropertyValues方法做进一步的处理。
//返回false的意思是告诉spring,不需要再调用下面的postProcessPropertyValues方法做处理了。
if(bean instanceof UserServiceImpl) {
return true;
}
return false;
}
@Override
public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
//测试二:如果在上面的方法里面返回了true,那么本方法会被调用,开发者可以做一些自定义的业务处理。
//举例来说:比如说spring服务启动后需要将该服务部署的机器的ip地址和端口注入到某个bean中去,那么
//就可以用下面的代码段做处理。
if(bean instanceof UserServiceImpl) {
MutablePropertyValues mpvs = (MutablePropertyValues) pvs;
mpvs.addPropertyValue(new PropertyValue("ip", "192.168.1.110"));
mpvs.addPropertyValue(new PropertyValue("port", "8080"));
}
return pvs;
}
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
//在本方法内主要是三种用法:一个是对bean做自定义的一些初始化或者修改的工作;一个是返回一个bean的代理对象;
// 一个是创建一个全新的bean,替换spring创建的bean。至于哪种用法,完全由开发者自己业务需求决定。
System.out.println("Execute postProcessBeforeInitialization.");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
//再本方法内主要是三种用法:一个是对bean做自定义的一些初始化或者修改的工作;一个是返回一个bean的代理对象;
// 一个是创建一个全新的bean,替换spring创建的bean。至于哪种用法,完全由开发者自己业务需求决定。
System.out.println("Execute postProcessAfterInitialization.");
return bean;
}
}
第四步:配置applicationContext.xml文件内容:文章源自JAVA秀-https://www.javaxiu.com/19880.html
<context:component-scan base-package="com.minesoft.tutorial" />
第五步:开始下面的测试。注意:第三步中的测试一和测试二是互斥的,做测试的时候选择测试一需要注释测试二的代码,选择测试二需要注释测试一的代码。文章源自JAVA秀-https://www.javaxiu.com/19880.html
ClassPathXmlApplicationContext cac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = cac.getBean(UserService.class);
System.out.println("address2" + userService);
运行上述测试一所对应的测试代码,控制台会打印如下的日志文章源自JAVA秀-https://www.javaxiu.com/19880.html
address1com.minesoft.tutorial.service.UserServiceImpl@3b2cf7ab
address2com.minesoft.tutorial.service.UserServiceImpl@3b2cf7ab文章源自JAVA秀-https://www.javaxiu.com/19880.html
两个相同的内存地址表明postProcessBeforeInstantiation中创建的bean和后面通过getBean方法拿到的就是同一个bean。也就说明了UserServiceImpl这个bean是开发者自己创建的,而不是spring创建的。文章源自JAVA秀-https://www.javaxiu.com/19880.html
ClassPathXmlApplicationContext cac = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
UserService userService = cac.getBean(UserService.class);
userService.findUserById(100L);
运行上述测试二的所对应的测试代码,控制台会打印如下的日志:文章源自JAVA秀-https://www.javaxiu.com/19880.html
ip: 192.168.1.110
port: 8080文章源自JAVA秀-https://www.javaxiu.com/19880.html
说明UserServiceImpl的ip和port属性都被成功的初始化了。文章源自JAVA秀-https://www.javaxiu.com/19880.html
文章源自JAVA秀-https://www.javaxiu.com/19880.html
更多知识请关注公众号文章源自JAVA秀-https://www.javaxiu.com/19880.html

评论