Skip to content

Commit

Permalink
Merge pull request #26 from microsphere-projects/dev
Browse files Browse the repository at this point in the history
Daily SNAPSHOT Updates
  • Loading branch information
mercyblitz authored Nov 22, 2024
2 parents 95923c1 + 7ab2068 commit cf8ff58
Show file tree
Hide file tree
Showing 19 changed files with 2,125 additions and 4 deletions.
5 changes: 5 additions & 0 deletions microsphere-spring-context/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,11 @@
<optional>true</optional>
</dependency>

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-indexer</artifactId>
<optional>true</optional>
</dependency>

<!-- Spring Data Redis -->
<dependency>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.microsphere.spring.beans.factory.support;

import io.microsphere.spring.util.SpringFactoriesLoaderUtils;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.AutowireCandidateResolver;
import org.springframework.core.annotation.AnnotationAwareOrderComparator;
import org.springframework.lang.Nullable;

import java.util.LinkedList;
import java.util.List;

import static io.microsphere.spring.util.BeanUtils.getSortedBeans;
import static io.microsphere.spring.util.SpringFactoriesLoaderUtils.loadFactories;
import static java.util.Collections.unmodifiableList;
import static org.springframework.core.annotation.AnnotationAwareOrderComparator.sort;

/**
* The Event Listener interface for the resolving processing including:
* <ul>
* <li>{@link AutowireCandidateResolver#getSuggestedValue(DependencyDescriptor) resolving suggested value}</li>
* <li>{@link AutowireCandidateResolver#getLazyResolutionProxyIfNecessary(DependencyDescriptor, String) resolving lazy proxy}</li>
* <li>{@link AutowireCandidateResolver#getLazyResolutionProxyClass(DependencyDescriptor, String) resolving lazy proxy class}</li>
* </ul>
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy<a/>
* @see ListenableAutowireCandidateResolver
* @see LoggingAutowireCandidateResolvingListener
* @see AutowireCandidateResolver
* @since 1.0.0
*/
public interface AutowireCandidateResolvingListener {

/**
* Loads {@link AutowireCandidateResolvingListener the listeners} from
* {@link SpringFactoriesLoaderUtils#loadFactories(BeanFactory, Class) Spring SPI with extension} and
* {@link ListableBeanFactory#getBeansOfType Beans}
*
* @param beanFactory {@link BeanFactory}
* @return the {@link AnnotationAwareOrderComparator#sort(List) sorted} {@link List} of
* {@link AutowireCandidateResolvingListener the listeners}
* @see SpringFactoriesLoaderUtils#loadFactories(BeanFactory, Class)
*/
static List<AutowireCandidateResolvingListener> loadListeners(@Nullable BeanFactory beanFactory) {
List<AutowireCandidateResolvingListener> listeners = new LinkedList<>();
// Add all Spring SPI with extension
listeners.addAll(loadFactories(beanFactory, AutowireCandidateResolvingListener.class));
// Add all Spring Beans if BeanFactory is available
if (beanFactory instanceof ListableBeanFactory lbf) {
listeners.addAll(getSortedBeans(lbf, AutowireCandidateResolvingListener.class));
}
// Sort
sort(listeners);
return unmodifiableList(listeners);
}

/**
* The event raised after {@link AutowireCandidateResolver#getSuggestedValue(DependencyDescriptor)} called
*
* @param descriptor {@link DependencyDescriptor the descriptor for the target method parameter or field}
* @param suggestedValue the value suggested (typically an expression String), or null if none found
*/
default void suggestedValueResolved(DependencyDescriptor descriptor, @Nullable Object suggestedValue) {
}

/**
* The event raised after {@link AutowireCandidateResolver#getLazyResolutionProxyIfNecessary(DependencyDescriptor, String)} called
*
* @param descriptor the descriptor for the target method parameter or field
* @param beanName the name of the bean that contains the injection point
* @param proxy the lazy resolution proxy for the actual dependency target,
* or {@code null} if straight resolution is to be performed
*/
default void lazyProxyResolved(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Object proxy) {
}

/**
* The event raised after {@link AutowireCandidateResolver#getLazyResolutionProxyClass(DependencyDescriptor, String)}
* called
*
* @param descriptor the descriptor for the target method parameter or field
* @param beanName the name of the bean that contains the injection point
* @param proxyClass the lazy resolution proxy class for the dependency target
* @see AutowireCandidateResolver#getLazyResolutionProxyClass(DependencyDescriptor, String)
*/
default void lazyProxyClassResolved(DependencyDescriptor descriptor, @Nullable String beanName, @Nullable Class<?> proxyClass) {
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.microsphere.spring.beans.factory.support;

import org.springframework.beans.factory.config.DependencyDescriptor;

import java.util.LinkedList;
import java.util.List;

import static io.microsphere.collection.CollectionUtils.isNotEmpty;
import static io.microsphere.collection.ListUtils.forEach;
import static org.springframework.core.annotation.AnnotationAwareOrderComparator.sort;
import static org.springframework.util.Assert.isTrue;
import static org.springframework.util.Assert.notNull;

/**
* The composite class for {@link AutowireCandidateResolvingListener}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy<a/>
* @see AutowireCandidateResolvingListener
* @since 1.0.0
*/
public class CompositeAutowireCandidateResolvingListener implements AutowireCandidateResolvingListener {

private final List<AutowireCandidateResolvingListener> listeners = new LinkedList<>();

public CompositeAutowireCandidateResolvingListener(List<AutowireCandidateResolvingListener> listeners) {
isTrue(isNotEmpty(listeners), "The argument 'listeners' must not be empty!");
this.addListeners(listeners);
}

public void addListeners(List<AutowireCandidateResolvingListener> listeners) {
forEach(listeners, listener -> {
notNull(listener, "The element 'listener' must not be null!");
this.listeners.add(listener);
});
sort(this.listeners);
}

@Override
public void suggestedValueResolved(DependencyDescriptor descriptor, Object suggestedValue) {
forEach(listeners, listener -> listener.suggestedValueResolved(descriptor, suggestedValue));
}

@Override
public void lazyProxyResolved(DependencyDescriptor descriptor, String beanName, Object proxy) {
forEach(listeners, listener -> listener.lazyProxyResolved(descriptor, beanName, proxy));
}

@Override
public void lazyProxyClassResolved(DependencyDescriptor descriptor, String beanName, Class<?> proxyClass) {
forEach(listeners, listener -> listener.lazyProxyClassResolved(descriptor, beanName, proxyClass));
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.microsphere.spring.beans.factory.support;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;
import org.springframework.beans.factory.support.AutowireCandidateResolver;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.lang.Nullable;

import java.util.Arrays;
import java.util.List;

import static io.microsphere.spring.beans.factory.support.AutowireCandidateResolvingListener.loadListeners;
import static io.microsphere.spring.util.BeanFactoryUtils.asDefaultListableBeanFactory;
import static io.microsphere.util.ArrayUtils.combine;

/**
* The decorator class of {@link AutowireCandidateResolver} to listen to the resolving process of autowire candidate by
* {@link AutowireCandidateResolvingListener}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy<a/>
* @see AutowireCandidateResolver
* @see AutowireCandidateResolvingListener
* @see CompositeAutowireCandidateResolvingListener
* @see DefaultListableBeanFactory#setAutowireCandidateResolver(AutowireCandidateResolver)
* @see BeanFactoryPostProcessor
* @since 1.0.0
*/
public class ListenableAutowireCandidateResolver implements AutowireCandidateResolver, BeanFactoryPostProcessor {

private AutowireCandidateResolver delegate;

private CompositeAutowireCandidateResolvingListener compositeListener;

private ConfigurableListableBeanFactory beanFactory;

public ListenableAutowireCandidateResolver() {
}

public void addListener(AutowireCandidateResolvingListener one, AutowireCandidateResolvingListener... more) {
addListeners(combine(one, more));
}

public void addListeners(AutowireCandidateResolvingListener[] listeners) {
addListeners(Arrays.asList(listeners));
}

public void addListeners(List<AutowireCandidateResolvingListener> listeners) {
compositeListener.addListeners(listeners);
}

@Override
public boolean isAutowireCandidate(BeanDefinitionHolder bdHolder, DependencyDescriptor descriptor) {
return delegate.isAutowireCandidate(bdHolder, descriptor);
}

@Override
public boolean isRequired(DependencyDescriptor descriptor) {
return delegate.isRequired(descriptor);
}

@Override
public boolean hasQualifier(DependencyDescriptor descriptor) {
return delegate.hasQualifier(descriptor);
}

@Nullable
@Override
public Object getSuggestedValue(DependencyDescriptor descriptor) {
Object suggestedValue = delegate.getSuggestedValue(descriptor);
compositeListener.suggestedValueResolved(descriptor, suggestedValue);
return suggestedValue;
}

@Nullable
@Override
public Object getLazyResolutionProxyIfNecessary(DependencyDescriptor descriptor, String beanName) {
Object proxy = delegate.getLazyResolutionProxyIfNecessary(descriptor, beanName);
compositeListener.lazyProxyResolved(descriptor, beanName, proxy);
return proxy;
}

@Nullable
@Override
public Class<?> getLazyResolutionProxyClass(DependencyDescriptor descriptor, String beanName) {
Class<?> proxyClass = delegate.getLazyResolutionProxyClass(descriptor, beanName);
compositeListener.lazyProxyClassResolved(descriptor, beanName, proxyClass);
return proxyClass;
}

@Override
public AutowireCandidateResolver cloneIfNecessary() {
return delegate.cloneIfNecessary();
}

@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
wrap(beanFactory);
}

/**
* Wraps {@link AutowireCandidateResolver} as the {@link ListenableAutowireCandidateResolver} and then register to
* the given {@link DefaultListableBeanFactory}
*
* @param beanFactory {@link DefaultListableBeanFactory}
*/
public void wrap(BeanFactory beanFactory) {
DefaultListableBeanFactory dbf = asDefaultListableBeanFactory(beanFactory);
AutowireCandidateResolver autowireCandidateResolver = dbf.getAutowireCandidateResolver();
if (autowireCandidateResolver != null) {
List<AutowireCandidateResolvingListener> listeners = loadListeners(beanFactory);
CompositeAutowireCandidateResolvingListener compositeListener = new CompositeAutowireCandidateResolvingListener(listeners);
this.delegate = autowireCandidateResolver;
this.compositeListener = compositeListener;
dbf.setAutowireCandidateResolver(this);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.microsphere.spring.beans.factory.support;

import io.microsphere.logging.Logger;
import io.microsphere.logging.LoggerFactory;
import org.springframework.beans.factory.config.DependencyDescriptor;

/**
* {@link Logger logging} {@link AutowireCandidateResolvingListener}
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy<a/>
* @see AutowireCandidateResolvingListener
* @see Logger
* @since 1.0.0
*/
public class LoggingAutowireCandidateResolvingListener implements AutowireCandidateResolvingListener {

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

@Override
public void suggestedValueResolved(DependencyDescriptor descriptor, Object suggestedValue) {
if (suggestedValue != null) {
if (logger.isInfoEnabled()) {
logger.info("The suggested value for {} was resolved : {}", descriptor, suggestedValue);
}
}
}

@Override
public void lazyProxyResolved(DependencyDescriptor descriptor, String beanName, Object proxy) {
if (proxy != null) {
if (logger.isInfoEnabled()) {
logger.info("The lazy proxy[descriptor : {} , bean name : '{}'] was resolved : {}", descriptor, beanName, proxy);
}
}
}

@Override
public void lazyProxyClassResolved(DependencyDescriptor descriptor, String beanName, Class<?> proxyClass) {
if (proxyClass != null) {
if (logger.isInfoEnabled()) {
logger.info("The lazy proxy class [descriptor : {} , bean name : '{}'] was resolved : {}", descriptor, beanName, proxyClass);
}
}
}

}
Loading

0 comments on commit cf8ff58

Please sign in to comment.