Skip to content

Commit

Permalink
【spring】优化
Browse files Browse the repository at this point in the history
  • Loading branch information
yong.teng committed Nov 12, 2023
1 parent 523064a commit 4c2215d
Show file tree
Hide file tree
Showing 6 changed files with 172 additions and 96 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,14 @@
package com.buession.canal.spring.annotation;

import com.buession.canal.annotation.CanalBinding;
import com.buession.canal.spring.binding.factory.CanalBindingFactoryBean;
import com.buession.core.validator.Validate;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.aop.scope.ScopedProxyFactoryBean;
import org.springframework.aop.scope.ScopedProxyUtils;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
Expand All @@ -48,9 +48,7 @@
import org.springframework.lang.NonNull;
import org.springframework.util.ClassUtils;

import java.util.Arrays;
import java.util.Optional;
import java.util.Set;

/**
* {@link CanalBinding} 扫描器
Expand All @@ -65,6 +63,8 @@ class CanalBindingClassPathMapperScanner extends ClassPathBeanDefinitionScanner
*/
private boolean lazyInitialization;

private final AutowireCapableBeanFactory beanFactory;

private final static Logger logger = LoggerFactory.getLogger(CanalBindingClassPathMapperScanner.class);

/**
Expand All @@ -76,10 +76,13 @@ class CanalBindingClassPathMapperScanner extends ClassPathBeanDefinitionScanner
* {@link Environment}
* @param resourceLoader
* {@link ResourceLoader}
* @param beanFactory
* {@link AutowireCapableBeanFactory}
*/
public CanalBindingClassPathMapperScanner(BeanDefinitionRegistry registry, Environment environment,
ResourceLoader resourceLoader) {
ResourceLoader resourceLoader, AutowireCapableBeanFactory beanFactory) {
super(registry, false, environment, resourceLoader);
this.beanFactory = beanFactory;
addIncludeFilter(new AnnotationTypeFilter(CanalBinding.class));
setBeanNameGenerator(FullyQualifiedAnnotationBeanNameGenerator.INSTANCE);
}
Expand All @@ -106,41 +109,19 @@ protected boolean checkCandidate(@NonNull String beanName, @NonNull BeanDefiniti
return true;
}else{
if(logger.isDebugEnabled()){
logger.warn("Skipping CanalBindingFactoryBean with name '{}' and '{}' bindingType" +
". Bean already defined with the same name!", beanName, beanDefinition.getBeanClassName());
logger.warn(
"Skipping CanalBindingFactoryBean with name '{}' and '{}' bindingType. Bean already defined with the same name!",
beanName, beanDefinition.getBeanClassName());
}
return false;
}
}

@Override
@NonNull
protected Set<BeanDefinitionHolder> doScan(@NonNull String... basePackages) {
Set<BeanDefinitionHolder> beanDefinitions = super.doScan(basePackages);

if(beanDefinitions.isEmpty()){
if(logger.isDebugEnabled()){
logger.debug("No CanalBinding was found in '{}' package. Please check your configuration.",
Arrays.toString(basePackages));
}
}else{
processBeanDefinitions(beanDefinitions);
}

return beanDefinitions;
}
protected void registerBeanDefinition(BeanDefinitionHolder definitionHolder, BeanDefinitionRegistry registry) {
super.registerBeanDefinition(definitionHolder, registry);

private void processBeanDefinitions(final Set<BeanDefinitionHolder> beanDefinitions) {
BeanDefinitionRegistry beanDefinitionRegistry = getRegistry();

for(BeanDefinitionHolder beanDefinitionHolder : beanDefinitions){
processBeanDefinition(beanDefinitionHolder, beanDefinitionRegistry);
}
}

private void processBeanDefinition(final BeanDefinitionHolder beanDefinitionHolder,
final BeanDefinitionRegistry beanDefinitionRegistry) {
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) beanDefinitionHolder.getBeanDefinition();
AbstractBeanDefinition beanDefinition = (AbstractBeanDefinition) definitionHolder.getBeanDefinition();

boolean scopedProxy = false;

Expand All @@ -149,58 +130,49 @@ private void processBeanDefinition(final BeanDefinitionHolder beanDefinitionHold
.ofNullable(((RootBeanDefinition) beanDefinition).getDecoratedDefinition())
.map(BeanDefinitionHolder::getBeanDefinition).orElseThrow(()->new IllegalStateException(
"The target bean definition of scoped proxy bean not found. Root bean definition[" +
beanDefinitionHolder + "]"));
definitionHolder + ']'));
scopedProxy = true;
}

processBeanDefinition(beanDefinitionHolder, beanDefinition);
processBeanDefinition(beanDefinition);

if(scopedProxy){
return;
}

if(beanDefinition.isSingleton() == false){
registerProxyBeanDefinitionHolder(beanDefinitionHolder, beanDefinitionRegistry);
registerProxyBeanDefinitionHolder(definitionHolder, registry);
}
}

private void processBeanDefinition(final BeanDefinitionHolder beanDefinitionHolder,
final AbstractBeanDefinition beanDefinition) {
private void processBeanDefinition(final AbstractBeanDefinition beanDefinition) {
String beanClassName = beanDefinition.getBeanClassName();
if(logger.isDebugEnabled()){
logger.debug("Creating CanalBindingFactoryBean with name '{}' and '{}' bindingType",
beanDefinitionHolder.getBeanName(), beanClassName);
}

Class<?> bindingClazz = ClassUtils.resolveClassName(beanClassName, null);
CanalBinding canalBinding = AnnotationUtils.findAnnotation(bindingClazz, CanalBinding.class);
CanalBinding canalBinding = AnnotationUtils.findAnnotation(ClassUtils.resolveClassName(beanClassName, null),
CanalBinding.class);

if(Validate.isBlank(canalBinding.destination())){
throw new IllegalStateException(
"Either 'destination' must be provided in @CanalBinding for: " + bindingClazz.getName());
"Either 'destination' must be required in @CanalBinding for: " + beanClassName);
}

beanDefinition.getPropertyValues().add("destination", canalBinding.destination());
beanDefinition.getPropertyValues().add("bindingType", bindingClazz);

beanDefinition.setBeanClass(CanalBindingFactoryBean.class);
beanDefinition.getConstructorArgumentValues().addGenericArgumentValue(beanClassName);

beanDefinition.setLazyInit(lazyInitialization);
beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
beanDefinition.setAttribute(FactoryBean.OBJECT_TYPE_ATTRIBUTE, beanClassName);

//CanalEventListenerAnnotationUtils.registryEventListenerMethod(canalBinding.destination(), );
}

private void registerProxyBeanDefinitionHolder(final BeanDefinitionHolder beanDefinitionHolder,
final BeanDefinitionRegistry beanDefinitionRegistry) {
final BeanDefinitionHolder proxyBeanDefinitionHolder = ScopedProxyUtils.createScopedProxy(beanDefinitionHolder,
beanDefinitionRegistry, true);
private void registerProxyBeanDefinitionHolder(final BeanDefinitionHolder definitionHolder,
final BeanDefinitionRegistry registry) {
final BeanDefinitionHolder proxyBeanDefinitionHolder = ScopedProxyUtils.createScopedProxy(definitionHolder,
registry, true);

if(beanDefinitionRegistry.containsBeanDefinition(proxyBeanDefinitionHolder.getBeanName())){
beanDefinitionRegistry.removeBeanDefinition(proxyBeanDefinitionHolder.getBeanName());
if(registry.containsBeanDefinition(proxyBeanDefinitionHolder.getBeanName())){
registry.removeBeanDefinition(proxyBeanDefinitionHolder.getBeanName());
}
beanDefinitionRegistry.registerBeanDefinition(proxyBeanDefinitionHolder.getBeanName(),
registry.registerBeanDefinition(proxyBeanDefinitionHolder.getBeanName(),
proxyBeanDefinitionHolder.getBeanDefinition());
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,15 @@
package com.buession.canal.spring.annotation;

import com.buession.canal.annotation.CanalBinding;
import com.buession.canal.client.dispatcher.DefaultDispatcher;
import com.buession.canal.spring.annotation.factory.CanalBindingBeanPostProcessor;
import com.buession.core.validator.Validate;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.AutowireCapableBeanFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.ResourceLoaderAware;
Expand All @@ -49,37 +56,46 @@
* @see BeanDefinition
* @since 0.0.1
*/
class CanalBindingScannerRegistrar implements ImportBeanDefinitionRegistrar, ResourceLoaderAware, EnvironmentAware {
class CanalBindingScannerRegistrar implements ImportBeanDefinitionRegistrar, EnvironmentAware, ResourceLoaderAware,
BeanFactoryAware {

private Environment environment;

private ResourceLoader resourceLoader;

public Environment getEnvironment() {
return environment;
}
private AutowireCapableBeanFactory beanFactory;

@Override
public void setEnvironment(@NonNull Environment environment) {
this.environment = environment;
}

public ResourceLoader getResourceLoader() {
return resourceLoader;
}

@Override
public void setResourceLoader(@NonNull ResourceLoader resourceLoader) {
this.resourceLoader = resourceLoader;
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
if(beanFactory instanceof AutowireCapableBeanFactory){
this.beanFactory = (AutowireCapableBeanFactory) beanFactory;
}
}

@Override
public void registerBeanDefinitions(@NonNull AnnotationMetadata metadata,
@NonNull BeanDefinitionRegistry registry) {
registerCanalBindingBeanDefinitions(metadata, registry);
registerDispatcherBeanDefinition(metadata, registry);
registerCanalBindingBeanPostProcessor(metadata, registry);
}

private void registerCanalBindingBeanDefinitions(final AnnotationMetadata metadata,
final BeanDefinitionRegistry registry) {
final AnnotationAttributes annotationAttributes = AnnotationAttributes.fromMap(
metadata.getAnnotationAttributes(EnableCanal.class.getName()));
final CanalBindingClassPathMapperScanner scanner = new CanalBindingClassPathMapperScanner(registry,
getEnvironment(), getResourceLoader());
environment, resourceLoader, beanFactory);
final Set<String> basePackages = getBasePackages(annotationAttributes);

String lazyInitialization = annotationAttributes.getString("lazyInitialization");
Expand All @@ -91,7 +107,23 @@ public void registerBeanDefinitions(@NonNull AnnotationMetadata metadata,
basePackages.add(getDefaultBasePackage(metadata));
}

scanner.doScan(basePackages.toArray(new String[]{}));
scanner.scan(basePackages.toArray(new String[]{}));
}

private void registerDispatcherBeanDefinition(final AnnotationMetadata metadata,
final BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(DefaultDispatcher.class);

registry.registerBeanDefinition("default.Canal.Dispatcher", builder.getBeanDefinition());
}

private void registerCanalBindingBeanPostProcessor(final AnnotationMetadata metadata,
final BeanDefinitionRegistry registry) {
BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition(
CanalBindingBeanPostProcessor.class);
builder.addPropertyValue("beanFactory", beanFactory);

registry.registerBeanDefinition(CanalBindingBeanPostProcessor.class.getName(), builder.getBeanDefinition());
}

private static Set<String> getBasePackages(final AnnotationAttributes annotationAttributes) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,10 +21,64 @@
* | Author: Yong.Teng <[email protected]> |
* | Copyright @ 2013-2023 Buession.com Inc. |
* +-------------------------------------------------------------------------------------------------------+
*/package com.buession.canal.spring.annotation.factory;/**
*
*
*/
package com.buession.canal.spring.annotation.factory;

import com.buession.canal.annotation.CanalBinding;
import com.buession.canal.annotation.CanalEventListener;
import com.buession.canal.client.dispatcher.AbstractDispatcher;
import com.buession.canal.client.dispatcher.Dispatcher;
import com.buession.canal.core.listener.utils.EventListenerUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.AnnotationUtils;
import org.springframework.lang.NonNull;
import org.springframework.util.ReflectionUtils;

import java.lang.reflect.Method;

/**
* @author Yong.Teng
* @since 0.0.1
*/public class CanalBindingBeanPostProcessor {
*/
public class CanalBindingBeanPostProcessor implements BeanPostProcessor, BeanFactoryAware {

private BeanFactory beanFactory;

@Override
public void setBeanFactory(@NonNull BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}

@Override
public Object postProcessAfterInitialization(@NonNull Object bean, @NonNull String beanName) throws BeansException {
CanalBinding canalBinding = AnnotationUtils.findAnnotation(bean.getClass(), CanalBinding.class);
if(canalBinding != null){
Dispatcher dispatcher = beanFactory.getBean(Dispatcher.class);
detectBindingMethods(bean, bean.getClass(), (AbstractDispatcher) dispatcher, canalBinding.destination());
}

return bean;
}

protected void detectBindingMethods(final Object bean, final Class<?> beanType, final AbstractDispatcher dispatcher,
final String destination) {
ReflectionUtils.doWithMethods(beanType, (method)->{
Method invocableMethod = AopUtils.selectInvocableMethod(method, beanType);
CanalEventListener canalEventListener = AnnotationUtils.findAnnotation(invocableMethod,
CanalEventListener.class);

if(canalEventListener == null){
return;
}

String listenerName = EventListenerUtils.buildEventListenerName(destination, canalEventListener.schema(),
canalEventListener.table(), canalEventListener.eventType());
dispatcher.getEventListenerRegistry().register(listenerName, bean, invocableMethod);
});
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@
* @author Yong.Teng
* @since 0.0.1
*/
package com.buession.canal.spring.annotation;
package com.buession.canal.spring.annotation.factory;
Loading

0 comments on commit 4c2215d

Please sign in to comment.