git: GitHub.com/service103699437…
Давайте поговорим о проблеме
Я изолирован дома, и у меня много свободного времени, у меня есть только время на то, чтобы разобраться с кодом в проекте, это так называемый рефакторинг, но у меня явно нет соответствующего опыта и знаний, я просто хочу реализовать некоторое наследование в java, использовать шаблоны проектирования и тому подобное.
Однако из-за существования весны некоторые вещи не могут быть легко доведены до весны, и их часто необходимо проверять.
Например, есть несколько реализаций интерфейса, есть повторяющиеся коды, это надо поднимать, я упомяну об этом в абстрактном классе.
Затем возникает проблема: абстрактный класс не может быть создан, поэтому его нельзя поместить в контейнер Spring, но в абстрактный класс необходимо внедрить другой Бин.
насколько я понимаю
- Свойства (поля) bean-компонентов, размещенных в контейнере Spring, могут быть @Autowired, это не вызывает споров.
- Класс, не помещенный в контейнер Spring, не может быть @Autowired, потому что Spring закрывает глаза на этот класс.
- Так,Могут ли поля родительского класса, которые явно не помещены в spring (то есть добавить @Component и т. д.), быть @Autowired?
Для программирования Baidu
Baidu получил следующие результаты:
-
woo woo woo.cn blog on.com/this Offering256/afraid/9…
Заключение по статье: пока свойство, которое будет внедрено родительским классом, является защищенным уровнем защиты (свойство родительского класса в тексте изначально было по умолчанию) -
woo woo woo.cn blog on.com/wow LS on/afraid/38…
Вывод статьи: метод super.set/атрибут родительского класса защищен от приватного, а метод автоматического внедрения подкласса (плюс аннотация автоматического внедрения) используется для установки атрибута в подклассе -
Woohoo.ITeye.com/blog/Arthur…
Заключение статьи: объявить свойство как защищенное в абстрактном классе и использовать метод аннотации для внедрения свойства
Честно говоря, это немного меньше, чем получить, защищенный еще имеет такой волшебный эффект?
практиковать самостоятельно
Напишем простой пример, как показано на рисунке:
@RestController
public class Controller {
@Qualifier("impl1")
// @Qualifier("impl2")
@Autowired
Service service;
public void save(){
service.save();
}
}
После экспериментов можно обнаружить, что когда @Qualifier используется для указания разных реализаций, Dao будет внедряться в бин подкласса, и проблем не будет.
Точка останова в исходном коде
getBean (beanName = контроллер)
Затем введите свойство populateBean(beanName=controller)
Внедрить bean-компонент с beanName=imp1 в контроллер
getBean (beanName = imp1) Используйте AutowiredAnnotationBeanPostProcessor, чтобы найти свойства, которые необходимо внедрить для imp1.
private InjectionMetadata buildAutowiringMetadata(final Class<?> clazz) {
if (!AnnotationUtils.isCandidateClass(clazz, this.autowiredAnnotationTypes)) {
return InjectionMetadata.EMPTY;
}
List<InjectionMetadata.InjectedElement> elements = new ArrayList<>();
Class<?> targetClass = clazz;
do {
final List<InjectionMetadata.InjectedElement> currElements = new ArrayList<>();
//这里找到需要注入的field
ReflectionUtils.doWithLocalFields(targetClass, field -> {
MergedAnnotation<?> ann = findAutowiredAnnotation(field);
if (ann != null) {
if (Modifier.isStatic(field.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static fields: " + field);
}
return;
}
boolean required = determineRequiredStatus(ann);
currElements.add(new AutowiredFieldElement(field, required));
}
});
ReflectionUtils.doWithLocalMethods(targetClass, method -> {
Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) {
return;
}
MergedAnnotation<?> ann = findAutowiredAnnotation(bridgedMethod);
if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) {
if (Modifier.isStatic(method.getModifiers())) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation is not supported on static methods: " + method);
}
return;
}
if (method.getParameterCount() == 0) {
if (logger.isInfoEnabled()) {
logger.info("Autowired annotation should only be used on methods with parameters: " +
method);
}
}
boolean required = determineRequiredStatus(ann);
PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz);
currElements.add(new AutowiredMethodElement(method, required, pd));
}
});
elements.addAll(0, currElements);
targetClass = targetClass.getSuperclass();
}
//注意这一句
while (targetClass != null && targetClass != Object.class);
return InjectionMetadata.forElements(elements, clazz);
}
При этом в то время как (targetClass != null && targetClass != Object.class) это предложение, первое в Поле, которое необходимо внедрить в ServiceImp1, не найдено, затем ищется в родительском классе AbstractService, и поле (то есть dao) находится с помощью getDeclaredFields(clazz)
Затем в соответствии с findAutowiredAnnotation найдите аннотацию @Autowired в поле и определите Dao, который будет введен в родительский класс.
@Nullable
private MergedAnnotation<?> findAutowiredAnnotation(AccessibleObject ao) {
MergedAnnotations annotations = MergedAnnotations.from(ao);
for (Class<? extends Annotation> type : this.autowiredAnnotationTypes) {
MergedAnnotation<?> annotation = annotations.get(type);
if (annotation.isPresent()) {
return annotation;
}
}
return null;
}
Конкретный процесс впрыска не анализируется.
В заключение
Подкласс передается в контейнер Spring, родительский класс не передается в контейнер Spring, и поля в родительском классе также могут быть автоматически введены
Суммировать
1: защищенный, упомянутый в результатах Baidu, фактически изменен с частного (или по умолчанию), и цель состоит только в том, чтобы разрешить подклассам доступ к нему. (В первой статье значение по умолчанию было изменено на защищенное. На самом деле, значения по умолчанию достаточно, когда подклассы находятся в одном пакете. Поэтому немного вводит в заблуждение, и это не слишком тщательно.)
Почему они изменили результаты, полученные Baidu, на защищенные?На самом деле, только ради строгости, protected означает, что подкласс может получить минимальное разрешение поля родительского класса.Результат поразил новичка вроде меня, хахахаха.
2: Хороший обзор частного:
При создании экземпляра подкласса по умолчанию вызывается конструктор родительского класса для инициализации родительского класса, то есть объект родительского класса создается в памяти, а затем уникальные атрибуты дочернего класса размещаются вне объекта родительского класса. ., вместе они становятся объектом подкласса. Следовательно, правильно, что подкласс наследует все свойства и методы родительского класса или что подкласс имеет все свойства и методы родительского класса, но подкласс не может напрямую обращаться к частным свойствам и методам родительского класса. . То есть он у вас просто есть, но вы не можете его использовать.
3: Drop Frame отладки IDEA действительно ароматный
немного побочного продукта
Реализация интерфейса postProcessMergedBeanDefinition из MergedBeanDefinitionPostProcessor отвечает за поиск атрибутов, которые необходимо внедрить
За реальную инъекцию отвечает интерфейс postProcessProperties InstantiationAwareBeanPostProcessor.
BeanPostProcessor действительно всеобъемлющий