>>>> 😜😜😜 Github: 👉 github.com/black-ant CASE Backup: 👉 gitee.com/antblack/ca…
A. The preface
BeanPostProcessor is one of the core components of Spring. Bean implementation Of BeanPostProcessor can achieve many complex functions
2. Structure of PostProcessor
2.1 Interface Methods
This interface provides two main types, including pre-call and post-call. You can also see that there’s a default modifier, so it’s not mandatory to override
public interface BeanPostProcessor {
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
returnbean; }}Copy the code
2.2 Common implementation classes
As you can see here, AOP, timing, configuration, and so on all implement relevant integrations
3. In-depth analysis of Spring source code
3.1 Use Cases
Take a look at this part of the Spring inside is how to use the PostProcessor characteristics, this part ScheduledAnnotationBeanPostProcessor, for example.
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
// As you can see, the pre-processing does not have much processing, and returns directly
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
if (bean instanceof AopInfrastructureBean || bean instanceof TaskScheduler ||
bean instanceof ScheduledExecutorService) {
// Ignore AOP infrastructure such as scoped proxies.
return bean;
}
// Step 1: Start special processingClass<? > targetClass = AopProxyUtils.ultimateTargetClass(bean);if (!this.nonAnnotatedClasses.contains(targetClass) &&
AnnotationUtils.isCandidateClass(targetClass, Arrays.asList(Scheduled.class, Schedules.class))) {
// Step 2: Get the collection of methods corresponding to the Scheduled changes
Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass,
(MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> {
Set<Scheduled> scheduledAnnotations = AnnotatedElementUtils.getMergedRepeatableAnnotations(
method, Scheduled.class, Schedules.class);
return(! scheduledAnnotations.isEmpty() ? scheduledAnnotations :null);
});
if (annotatedMethods.isEmpty()) {
this.nonAnnotatedClasses.add(targetClass);
}
else {
// Step 3: The method is not empty, execute ProcessannotatedMethods.forEach((method, scheduledAnnotations) -> scheduledAnnotations.forEach(scheduled -> processScheduled(scheduled, method, bean))); }}return bean;
}
Copy the code
PS: Running a Runable object through a ScheduledTask
From the specific use, it is not difficult to see that he is in the creation of Bean to do supplementary operations, so let’s look at the specific processing process
This process is fully traced through the Bean initialization process, with more attention to some of the details
3.2 Before/After invokes the process
Entrance to one: # AbstractAutowireCapableBeanFactory initializeBean calls
- applyBeanPostProcessorsBeforeInitialization
- applyBeanPostProcessorsAfterInitialization
The for loop processes all the BeanPostProcessors
3.3 Management of BeanPostProcessors
AbstractBeanFactory there is a collection in AbstractBeanFactory that manages the BeanPostProcessor
private final List<BeanPostProcessor> beanPostProcessors = new BeanPostProcessorCacheAwareList();
// Regardless of the type, the call is made in two ways: first delete, then add
public void addBeanPostProcessors(Collection<? extends BeanPostProcessor> beanPostProcessors) {
this.beanPostProcessors.removeAll(beanPostProcessors);
this.beanPostProcessors.addAll(beanPostProcessors);
}
public void addBeanPostProcessor(BeanPostProcessor beanPostProcessor) {
this.beanPostProcessors.remove(beanPostProcessor);
this.beanPostProcessors.add(beanPostProcessor);
}
Copy the code
Type 1: Manual adding process
Can be realized by manually add, add BeanPostProcessor, AbstractApplicationContext reference object
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
/ /...
// Configure the bean factory with context callbacks.
beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));
/ /...
}
Copy the code
Type 2: Refresh segment is added
Ha ha, here we go again. I noticed this place when I looked at the Refresh code earlier, registering the associated BeanPostProcessors
protected void registerBeanPostProcessors(ConfigurableListableBeanFactory beanFactory) {
/ / Step 1: call PostProcessorRegistrationDelegate to register
PostProcessorRegistrationDelegate.registerBeanPostProcessors(beanFactory, this);
}
Copy the code
Source code comments are very clear, here is a simple translation
public static void registerBeanPostProcessors( ConfigurableListableBeanFactory beanFactory, AbstractApplicationContext applicationContext) {
// postProcessor arraylist
String[] postProcessorNames = beanFactory.getBeanNamesForType(BeanPostProcessor.class, true.false);
/ / processor counting
int beanProcessorTargetCount = beanFactory.getBeanPostProcessorCount() + 1 + postProcessorNames.length;
// Register BeanPostProcessorChecker, which logs informational messages when the bean is created during BeanPostProcessor instantiation, that is, when the bean does not meet all criteria for BeanPostProcessors processing
beanFactory.addBeanPostProcessor(new BeanPostProcessorChecker(beanFactory, beanProcessorTargetCount));
// distinguish PriorityOrdered, internalPostProcessor
List<BeanPostProcessor> priorityOrderedPostProcessors = new ArrayList<>();
List<BeanPostProcessor> internalPostProcessors = new ArrayList<>();
/ / ordering
List<String> orderedPostProcessorNames = new ArrayList<>();
List<String> nonOrderedPostProcessorNames = new ArrayList<>();
for (String ppName : postProcessorNames) {
if (beanFactory.isTypeMatch(ppName, PriorityOrdered.class)) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
priorityOrderedPostProcessors.add(pp);
// The post-processor callback interface used at runtime to merge bean definitions
if (pp instanceofMergedBeanDefinitionPostProcessor) { internalPostProcessors.add(pp); }}// If the Ordered interface is implemented, Ordered processing is required
else if (beanFactory.isTypeMatch(ppName, Ordered.class)) {
orderedPostProcessorNames.add(ppName);
}
else{ nonOrderedPostProcessorNames.add(ppName); }}// First, register BeanPostProcessors that implement Prioritordered
sortPostProcessors(priorityOrderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, priorityOrderedPostProcessors);
// Next, register the BeanPostProcessors that implemented Ordered
List<BeanPostProcessor> orderedPostProcessors = new ArrayList<>(orderedPostProcessorNames.size());
for (String ppName : orderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
orderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
sortPostProcessors(orderedPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, orderedPostProcessors);
// Now, register all regular BeanPostProcessors
List<BeanPostProcessor> nonOrderedPostProcessors = new ArrayList<>(nonOrderedPostProcessorNames.size());
for (String ppName : nonOrderedPostProcessorNames) {
BeanPostProcessor pp = beanFactory.getBean(ppName, BeanPostProcessor.class);
nonOrderedPostProcessors.add(pp);
if (pp instanceof MergedBeanDefinitionPostProcessor) {
internalPostProcessors.add(pp);
}
}
registerBeanPostProcessors(beanFactory, nonOrderedPostProcessors);
// Finally, re-register all internal BeanPostProcessors
sortPostProcessors(internalPostProcessors, beanFactory);
registerBeanPostProcessors(beanFactory, internalPostProcessors);
// Re-register the post-handler used to detect the internal bean as ApplicationListeners, moving them to the end of the handler chain
beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(applicationContext));
}
Copy the code
4. In-depth customization
4.1 add BeanPostProcessor
Method 1: Add it manually
PS: Of course, this method is too complicated for many scenarios
@Autowired
private DefaultListableBeanFactory beanFactory;
@Bean(initMethod = "initMethod")
public CommonService getCommonService(a) {
// Add via BeanFactory
beanFactory.addBeanPostProcessor(new CustomizePostProcessor());
return new CommonService();
}
Copy the code
Method 2: Inherit the interface directly
As you can see from the above analysis, the interface is automatically added once implemented
5. Supplementary questions
5.1 What are the differences from the four common initialization methods?
Review the four ways to initialize a run:
- Implement the InitializingBean interface method afterPropertiesSet
- Implement ApplicationRunner interface method Run (ApplicationArguments args)
- Method annotation @postconstruct
- @bean (initMethod = “initMethod”) is specified by an annotation
Call difference
: -- -- -- -- -- - >this is @PostConstruct< -- -- -- -- -- -- -- : -- -- -- -- -- -- >this is InitializingBean <-------
: ------> this is in @Bean(initMethod = "initMethod")< -- -- -- -- -- -- -- : -- -- -- -- -- -- >this is postProcessBeforeInitialization <-------
: ------> this is postProcessAfterInitialization <-------
: ------> this is postProcessBeforeInitialization <-------
: ------> this is postProcessAfterInitialization <-------
: ------> this is postProcessBeforeInitialization <-------
: ------> this is postProcessAfterInitialization <-------
: Started DemoApplication in 0.822 seconds (JVM running for 2.597) : -- -- -- -- -- - >this is ApplicationRunner :getCommonService <-------
Copy the code
- Call number: four methods will be called only once, and postProcessBeforeInitialization and postProcessAfterInitialization will be called when each Bean created
- Call timing: Calls are focused on each Bean initializeBean link
Six. What can we do with it?
There is no discussion here about whether there is a real scene to use, just divergent thinking, to think about how to use its characteristics to do something
6.1 Combine design patterns
Proxying is one of the most appropriate uses of postProcess. AOP is proxying using its features. We can simulate AOP to do a more business-oriented static proxy pattern.
The decorator pattern can also be implemented to enhance Bean processing.
Step 1: Prepare interfaces and implementation classes
// Unified interface
public interface Sourceable {
void method(a);
}
// Corresponding implementation class (actual business class)
@Service
public class Source implements Sourceable {
@Override
public void method(a) {
System.out.println("the original method!"); }}Copy the code
Step 2: Prepare intermediate classes
public class AopProxyImpl implements Sourceable {
private Sourceable source;
public AopProxyImpl(Sourceable source) {
super(a);// Note that the proxy mode creates an object in the proxy class
// this.source = new Source();
// The decorator mode is passed in the corresponding object
this.source = source;
}
@Override
public void method(a) {
before();
source.method();
atfer();
}
private void atfer(a) {
System.out.println("after proxy!");
}
private void before(a) {
System.out.println("before proxy!"); }}Copy the code
Step 3: BeanPostProcessor
@Service
public class AopPostProcessor implements BeanPostProcessor {
private Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
logger.info("------> AopPostProcessor postProcessBeforeInitialization <-------");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
logger.info("------> AopPostProcessor postProcessAfterInitialization <-------");
if (bean instanceof Sourceable) {
logger.info("------> AopPostProcessor build Aop <-------");
AopProxyImpl proxy = new AopProxyImpl((Sourceable)bean);
return proxy;
}
returnbean; }}Copy the code
Supplement:
- Here if not, it will throw BeanNotOfRequiredTypeException, because Spring will go to stick to match
- Here we are static proxies, but we can use cglib dynamic proxies more flexibly
- There are many other ways to integrate design patterns that can be used flexibly
6.2 Manager Manages objects of a specified type
This is done by placing an administrative record on the specified Bean in the postProcessor
The approximate way to use it is to prepare a BeanManager and manage it in the postProcessor
@Component
public class BeanManager {
// Group special beans
private static Map<String, TypeBean> typeOne = new ConcurrentHashMap();
private static Map<String, TypeBean> typeTwo = new ConcurrentHashMap();
/ / PS: this way is suitable for processing more complex scenarios, may consider the simple scenario by ApplicationContext. GetBean to obtain the corresponding class
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
logger.info("------> ManagerPostProcessor postProcessAfterInitialization <-------");
if (bean instanceof TypeBean) {
logger.info("------> AopPostProcessor build Aop <-------");
beanManager.getTypeOne().put(beanName, (TypeBean) bean);
}
return bean;
}
// PS: actually the same object as the injected object
------> typeOne.get("typeBeanImpl") == (typeBean) :true <-------
Copy the code
Supplement:
This is the simplest way to use it, but more complex ways can be to integrate annotations, integrate interfaces or superclasses, or just record class information to achieve their own business effects
6.3 Injecting special Attributes
We can see from the picture that BeanPostProcessor is processed after the PopulateBean link, so we can modify the attributes in the Bean through this link. Common ideas include:
- Sets the dynamic proxy for a specific property
- Get the properties from the Remote and set them
This makes a lot of sense. In fact, at this point RestTemplate is loaded, JDBC is available, and you can get configuration information from the remote end
// Function 1:Using JDBC (JPA should also be loaded and available), get the configuration from the database, determine if the current class has a specific annotation, and refresh the annotation configuration// Function 2:Call the remote configuration center to customize the refresh configuration//Refresh special properties or objects and so onCopy the code
** Special object refresh has a variety of arbitrary use, can be used flexibly according to their own business
6.4 Other Ideas
This is just a piece of cake, welcome to put forward their own ideas
- Refactoring properties
- Classes are overridden during customization
conclusion
Note:
- ApplyBeanPostProcessorsBeforeInitialization mainly in initializeBean link calls
- ApplyBeanPostProcessorsAfterInitialization besides initializeBean also in multiple link is called, Including getSingletonFactoryBeanForTypeCheck, etc in the process of a few Factory to instantiate
- Avoid loops; ManagerPostProcessor does not process itself
- BeanPostProcessor is called every time a bean is created, and too much can affect startup efficiency
- BeanPostProcessor is mainly after populateBean, note the order