← Назад к вопросам

На каком этапе жизненного цикла Bean внедряется Proxy в Spring

2.8 Senior🔥 101 комментариев
#Spring Framework

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI22 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Жизненный цикл Bean и создание Proxy в Spring

Ответ: после инициализации Bean'а, перед помещением в контекст (на этапе post-initialization).

Жизненный цикл Bean в Spring

1. INSTANTIATION    - создание объекта
2. PROPERTY SETTING - установка зависимостей
3. INITIALIZATION   - инициализация (@PostConstruct, InitializingBean)
4. BPP POST-INIT    - BeanPostProcessor.postProcessAfterInitialization()
5. READY            - Bean готов к использованию в контексте

Proxy создается на этапе 4 - в методе postProcessAfterInitialization() BeanPostProcessor'а.

Этапы жизненного цикла подробнее

@Component
public class MyBean implements InitializingBean {
    
    // 1. INSTANTIATION - вызывается конструктор
    public MyBean() {
        System.out.println("1. Constructor called");
    }
    
    @Autowired
    private DependencyBean dependency;
    
    // 2. PROPERTY SETTING - установка @Autowired зависимостей
    // (невидимый этап, Spring делает это за кулисами)
    
    // 3. INITIALIZATION - вызовов @PostConstruct и afterPropertiesSet()
    @PostConstruct
    public void postConstruct() {
        System.out.println("3. @PostConstruct called");
    }
    
    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("3. InitializingBean.afterPropertiesSet() called");
    }
    
    // 4. BPP POST-INIT - здесь создается Proxy!
    // (внутренний этап, BeanPostProcessor.postProcessAfterInitialization())
    
    public void doSomething() {
        System.out.println("5. Bean ready to use");
    }
}

Вывод при загрузке контекста:

1. Constructor called
3. @PostConstruct called
3. InitializingBean.afterPropertiesSet() called
5. Bean ready to use

BeanPostProcessor и создание Proxy

BeanPostProcessor - это интерфейс для вмешательства в жизненный цикл:

public interface BeanPostProcessor {
    
    // Перед инициализацией
    default Object postProcessBeforeInitialization(Object bean, String beanName) {
        return bean;  // Можем вернуть обёртку (Proxy)
    }
    
    // После инициализации - ТУТ СОЗДАЕТСЯ PROXY!
    default Object postProcessAfterInitialization(Object bean, String beanName) {
        return bean;  // Можем вернуть Proxy вместо оригинального Bean
    }
}

Пример: создание Proxy вручную

@Component
public class LoggingBeanPostProcessor implements BeanPostProcessor {
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        
        // Проверяем, если Bean имеет @Loggable аннотацию
        if (bean.getClass().isAnnotationPresent(Loggable.class)) {
            
            // Создаём динамический Proxy
            return Proxy.newProxyInstance(
                bean.getClass().getClassLoader(),
                bean.getClass().getInterfaces(),
                (proxy, method, args) -> {
                    System.out.println("Calling: " + method.getName());
                    Object result = method.invoke(bean, args);
                    System.out.println("Result: " + result);
                    return result;
                }
            );
        }
        
        return bean;  // Возвращаем оригинальный Bean
    }
}

@Loggable
@Component
public class UserService {
    public String getUser(Long id) {
        return "User #" + id;
    }
}

// Использование
UserService service = context.getBean(UserService.class);
// Это не оригинальный UserService, а Proxy!

Spring AOP и Proxy создание

@Aspect создаёт Proxy через BeanPostProcessor:

@Aspect
@Component
public class LoggingAspect {
    
    // Этот advice завернет Bean в Proxy
    @Before("@annotation(Loggable)")
    public void logBefore(JoinPoint jp) {
        System.out.println("Before: " + jp.getSignature());
    }
}

@Component
@Loggable
public class UserService {
    public void saveUser(String name) {
        System.out.println("Saving user: " + name);
    }
}

// Использование
UserService service = context.getBean(UserService.class);
service.saveUser("John");

// Вывод:
// Before: void UserService.saveUser(..)
// Saving user: John

Основные BeanPostProcessor'ы в Spring

// 1. AutowiredAnnotationBeanPostProcessor
//    - Обрабатывает @Autowired, @Value
//    - На этапе PROPERTY SETTING

// 2. CommonAnnotationBeanPostProcessor
//    - Обрабатывает @PostConstruct, @PreDestroy
//    - На этапе INITIALIZATION

// 3. AbstractAutoProxyCreator (для AOP)
//    - Создаёт JDK или CGLIB Proxy
//    - На этапе POST-INIT (postProcessAfterInitialization)

// 4. ScheduledAnnotationBeanPostProcessor
//    - Регистрирует методы с @Scheduled

Важные моменты о Proxy

1. JDK Proxy vs CGLIB

JDK Proxy:

// Требует интерфейс
public interface UserService {
    void save(User user);
}

@Component
public class UserServiceImpl implements UserService {
    @Override
    public void save(User user) {
        // реализация
    }
}

// Spring создаст JDK Proxy (реализует UserService)
UserService service = context.getBean(UserService.class);  // OK
UserServiceImpl impl = context.getBean(UserServiceImpl.class);  // ОШИБКА!

CGLIB Proxy:

// Не требует интерфейс (работает с классами)
@Component
public class UserService {  // Нет интерфейса
    public void save(User user) {
        // реализация
    }
}

// Spring создаст CGLIB Proxy (наследует UserService)
UserService service = context.getBean(UserService.class);  // OK

2. Order (порядок выполнения BeanPostProcessor'ов)

@Component
@Order(1)  // Выполнится раньше
public class FirstBPP implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("First BPP: " + beanName);
        return bean;
    }
}

@Component
@Order(2)  // Выполнится позже
public class SecondBPP implements BeanPostProcessor {
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("Second BPP: " + beanName);
        return bean;
    }
}

Визуально: полный жизненный цикл

┌─────────────────────────────────────────┐
│  Spring контейнер запускается           │
└─────────────────────────────────────────┘
              ↓
┌─────────────────────────────────────────┐
│  1. INSTANTIATION - создание объекта    │
│     new MyBean()                        │
└─────────────────────────────────────────┘
              ↓
┌─────────────────────────────────────────┐
│  2. DEPENDENCY INJECTION - @Autowired    │
│     Внедрение зависимостей              │
└─────────────────────────────────────────┘
              ↓
┌─────────────────────────────────────────┐
│  3. INITIALIZATION - @PostConstruct      │
│     InitializingBean.afterPropertiesSet()
└─────────────────────────────────────────┘
              ↓
┌─────────────────────────────────────────┐
│  4. BPP.postProcessAfterInitialization() │
│     ⭐ PROXY СОЗДАЕТСЯ ЗДЕСЬ! ⭐        │
│     AbstractAutoProxyCreator.wrap()      │
└─────────────────────────────────────────┘
              ↓
┌─────────────────────────────────────────┐
│  5. READY - Bean готов в контексте      │
│     context.getBean() возвращает Proxy  │
└─────────────────────────────────────────┘

Пример: Custom Proxy создание

@Component
public class CustomProxyBPP implements BeanPostProcessor {
    
    private static final Logger log = LoggerFactory.getLogger(CustomProxyBPP.class);
    
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        
        Class<?> beanClass = bean.getClass();
        
        // Проверяем наличие @Transactional (для примера)
        if (beanClass.isAnnotationPresent(Transactional.class)) {
            
            log.info("Creating proxy for bean: {}", beanName);
            
            // Создаём Proxy (используя cglib в реальном коде)
            return ProxyFactory.createProxy(bean);
        }
        
        return bean;
    }
}

Часто задаваемые вопросы

Q: На каком этапе вызывается @PostConstruct? A: На этапе 3 - INITIALIZATION, перед постProcessAfterInitialization()

Q: Почему некоторые методы не работают в Proxy? A: Потому что Proxy оборачивает Bean. Методы должны вызываться через интерфейс (JDK) или быть переопределяемыми (CGLIB).

Q: Как избежать проблем с Proxy? A: Используй интерфейсы, работай с контрактом, не обращайся к конкретному классу.

Итоговый контрольный список

  • ✅ Proxy создается после инициализации Bean'а
  • ✅ На этапе postProcessAfterInitialization() BeanPostProcessor'а
  • ✅ Spring использует JDK Proxy (с интерфейсом) или CGLIB (без интерфейса)
  • ✅ AOP Proxy создается автоматически через AbstractAutoProxyCreator
  • ✅ Custom Proxy можно создать через собственный BeanPostProcessor