Középhaladó Olvasási idő: ~8 perc

ApplicationContext

BeanFactory vs ApplicationContext, XML config, Java config, annotation-based config

ApplicationContext

1. Definíció

Az ApplicationContext a Spring Framework központi interfésze, amely a teljes IoC container funkcionalitást biztosítja. A BeanFactory interfész leszármazottja, de azon túlmutatva integrált AOP-támogatást, nemzetköziesítést (i18n), eseménykezelést és environment-absztrakciót is kínál. A legtöbb Spring alkalmazás az ApplicationContext-et használja a BeanFactory helyett, mert az éles üzemhez szükséges szolgáltatások mind itt érhetők el.

A Spring Boot alkalmazásokban az ApplicationContext-et a SpringApplication.run() hozza létre automatikusan — általában AnnotationConfigServletWebServerApplicationContext típussal web alkalmazásoknál.


2. Alapfogalmak

BeanFactory vs ApplicationContext

Jellemző BeanFactory ApplicationContext
Bean létrehozás Lazy (első lekéréskor) Eager (induláskor singleton-ok)
Eseménykezelés ApplicationEventPublisher
i18n (MessageSource)
AOP integráció Kézi Automatikus
BeanPostProcessor regisztráció Kézi Automatikus
Environment / Profile
ResourceLoader Alapszintű Fejlett (classpath, file, URL)

A BeanFactory lightweight container, amely csak a bean-ek példányosítását és DI-t végzi. Az ApplicationContext mindent tartalmaz, amit a BeanFactory, plusz enterprise-szintű szolgáltatásokat.

Főbb ApplicationContext implementációk

  • AnnotationConfigApplicationContext — Java config (@Configuration osztályok) standalone alkalmazásban
  • ClassPathXmlApplicationContext — XML konfiguráció classpath-ról
  • GenericWebApplicationContext — Web környezet, servlet container integráció
  • AnnotationConfigServletWebServerApplicationContext — Spring Boot web alkalmazás (alapértelmezett)

Konfiguráció típusok

XML-alapú — A klasszikus megközelítés, <beans> gyökérelem, <bean> definíciók:

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="...">
    <bean id="dataSource" class="com.zaxxer.hikari.HikariDataSource">
        <property name="jdbcUrl" value="jdbc:h2:mem:test"/>
    </bean>
</beans>

Java config@Configuration + @Bean:

@Configuration
public class AppConfig {
    @Bean
    public DataSource dataSource() {
        HikariDataSource ds = new HikariDataSource();
        ds.setJdbcUrl("jdbc:h2:mem:test");
        return ds;
    }
}

Annotáció-alapú@ComponentScan + sztereotíp annotációk (@Component, @Service, @Repository):

@Configuration
@ComponentScan("com.example")
public class AppConfig {}

Gyakorlatban a legtöbb Spring Boot projekt a Java config + annotáció-alapú megközelítés kombinációját használja. XML config legacy kódban fordul elő.


3. Gyakorlati használat

Context indítás standalone alkalmazásban

// Java config
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = ctx.getBean(UserService.class);

// XML config (legacy)
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

Spring Boot alkalmazás

@SpringBootApplication
public class MyApp {
    public static void main(String[] args) {
        ApplicationContext ctx = SpringApplication.run(MyApp.class, args);
        // ctx automatikusan elérhető, ritkán kell kézzel lekérni bean-t
    }
}

Environment és Profile-ok

@Configuration
@Profile("production")
public class ProdConfig {
    @Bean
    public DataSource dataSource() {
        // production DataSource
    }
}

Aktiválás: spring.profiles.active=production (application.properties vagy JVM arg).

Eseménykezelés

// Esemény publikálás
@Service
public class OrderService {
    private final ApplicationEventPublisher publisher;

    public OrderService(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    public void placeOrder(Order order) {
        // üzleti logika
        publisher.publishEvent(new OrderPlacedEvent(order));
    }
}

// Esemény fogadás
@Component
public class NotificationListener {
    @EventListener
    public void onOrderPlaced(OrderPlacedEvent event) {
        // értesítés küldése
    }
}

i18n (MessageSource)

@Autowired
private MessageSource messageSource;

String msg = messageSource.getMessage("greeting", null, Locale.forLanguageTag("hu"));

4. Kód példák

Teljes Java config alkalmazás

@Configuration
@ComponentScan("com.example")
@PropertySource("classpath:app.properties")
public class AppConfig {

    @Value("${app.name}")
    private String appName;

    @Bean
    public AppInfo appInfo() {
        return new AppInfo(appName);
    }
}

Több config összekapcsolása

@Configuration
@Import({DataConfig.class, SecurityConfig.class})
public class RootConfig {}

Context hierarchia (parent-child)

AnnotationConfigApplicationContext parent = new AnnotationConfigApplicationContext(SharedConfig.class);
AnnotationConfigApplicationContext child = new AnnotationConfigApplicationContext();
child.setParent(parent);
child.register(WebConfig.class);
child.refresh();
// child context eléri a parent bean-jeit, fordítva nem

ResourceLoader használat

@Service
public class TemplateService {
    private final ResourceLoader resourceLoader;

    public TemplateService(ResourceLoader resourceLoader) {
        this.resourceLoader = resourceLoader;
    }

    public String loadTemplate(String path) throws IOException {
        Resource resource = resourceLoader.getResource("classpath:" + path);
        return new String(resource.getInputStream().readAllBytes());
    }
}

5. Trade-offok

Szempont Előny Hátrány
Eager initialization (singleton) Hibák induláskor kiderülnek (fail-fast) Lassabb indulás sok bean esetén
Java config vs XML Típusbiztos, IDE refactoring Bonyolultabb @Conditional logika
XML config Deklaratív, kódon kívüli módosítás Verbose, nincs compiler ellenőrzés
Annotáció-alapú config Minimális boilerplate Szétszórt konfiguráció, nehéz áttekinteni
@ComponentScan Automatikus, kevés kód Nem látszik, mi kerül a context-be
Explicit @Bean Teljes kontroll, dokumentált Több kód, karbantartás

Mikor melyik megközelítés?

  • Új projekt: Java config + annotációk (Spring Boot default)
  • Külső library bean: @Bean metódus @Configuration osztályban
  • Legacy integráció: @ImportResource("legacy-context.xml")
  • Feltételes bean: @Conditional* annotációk Java config-ban

6. Gyakori hibák

❌ Context manuális bezárás nélkül (standalone app)

// ROSSZ — erőforrás szivárgás
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
// használat...
// @PreDestroy callback-ek nem futnak le

// JÓ — try-with-resources
try (var ctx = new AnnotationConfigApplicationContext(AppConfig.class)) {
    ctx.getBean(MyService.class).doWork();
} // @PreDestroy automatikusan meghívódik

❌ BeanFactory használata ApplicationContext helyett

// ROSSZ — nincs AOP, nincs Event, nincs BeanPostProcessor auto-regisztráció
BeanFactory factory = new DefaultListableBeanFactory();

// JÓ — használj ApplicationContext-et
ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);

❌ Context refresh többszöri meghívása

// ROSSZ — duplikált bean-ek, memória szivárgás
ctx.refresh();
ctx.refresh();

❌ Rossz profile aktiválás

// ROSSZ — a profile-t a context refresh előtt kell beállítani
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.refresh();
ctx.getEnvironment().setActiveProfiles("prod"); // Nincs hatása!

// JÓ
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.getEnvironment().setActiveProfiles("prod");
ctx.register(AppConfig.class);
ctx.refresh();

7. Mélyebb összefüggések

Context lifecycle

  1. Bean definition betöltés@Configuration osztályok, XML fájlok parse-olása
  2. BeanFactoryPostProcessor futtatás — bean definíciók módosítása (pl. PropertySourcesPlaceholderConfigurer)
  3. Bean példányosítás — singleton bean-ek eager létrehozása
  4. BeanPostProcessor futtatás — AOP proxy, @Autowired feloldás
  5. Context readyContextRefreshedEvent publikálása
  6. Működés — bean-ek használata
  7. Context closeContextClosedEvent, @PreDestroy callback-ek

BeanFactoryPostProcessor vs BeanPostProcessor

Aspektus BeanFactoryPostProcessor BeanPostProcessor
Mikor fut? Bean definíciók betöltése után, példányosítás előtt Minden egyes bean példányosítása után
Mit módosít? Bean definíciókat (metaadatok) Bean példányokat
Tipikus használat Property placeholder feloldás, bean definíció módosítás AOP proxy, @Autowired, @PostConstruct

Context hierarchia (parent-child)

A Spring MVC klasszikus modellje: root context (service, repository bean-ek) és servlet context (controller-ek, view resolver-ek). A gyerek context látja a szülő bean-jeit, de fordítva nem. Spring Boot-ban ez egyszerűsödött — jellemzően egy flat context van.

@Configuration osztályok CGLIB proxy-ja

A @Configuration osztályokat a Spring CGLIB proxy-val tölti be. Ennek köszönhető, hogy a @Bean metódusok inter-bean referenciái (egy @Bean metódus meghív egy másikat) singleton szemantikát tartanak. Ha @Configuration(proxyBeanMethods = false) (lite mode), ez a viselkedés kikapcsol.

@Configuration
public class AppConfig {
    @Bean
    public ServiceA serviceA() {
        return new ServiceA(commonDep()); // CGLIB: singleton-t ad vissza
    }

    @Bean
    public ServiceB serviceB() {
        return new ServiceB(commonDep()); // CGLIB: UGYANAZT a példányt adja
    }

    @Bean
    public CommonDep commonDep() {
        return new CommonDep();
    }
}

8. Interjúkérdések

  1. Mi a különbség a BeanFactory és az ApplicationContext között? A BeanFactory az alapszintű DI container (lazy init), az ApplicationContext mindent tartalmaz + event, i18n, AOP, BeanPostProcessor auto-regisztráció, Environment.

  2. Milyen ApplicationContext implementációkat ismersz? AnnotationConfigApplicationContext, ClassPathXmlApplicationContext, GenericWebApplicationContext, Spring Boot: AnnotationConfigServletWebServerApplicationContext.

  3. Mi a különbség Java config és annotáció-alapú config között? Java config: explicit @Bean metódusok @Configuration osztályban. Annotáció-alapú: @ComponentScan + sztereotíp annotációk (@Component, @Service). Gyakorlatban kombinálják őket.

  4. Hogyan működik a @Configuration CGLIB proxy? A Spring CGLIB subclass-t hoz létre a @Configuration osztályból. Így az inter-bean referenciák (egy @Bean metódus meghív másikat) mindig a singleton cache-ből adják a példányt. proxyBeanMethods = false kikapcsolja.

  5. Mi a context lifecycle sorrendje? Bean definition load → BeanFactoryPostProcessor → Singleton instantiation → BeanPostProcessor → ContextRefreshedEvent → Usage → ContextClosedEvent → @PreDestroy.

  6. Mikor használnál XML config-ot 2024-ben? Legacy integráció, third-party framework kényszer, vagy ha a konfigurációt kódon kívül kell módosítani. Új projektben Java config az ajánlott.

  7. Mi a context hierarchia és mire jó? Parent-child context: a gyerek látja a szülő bean-jeit, de fordítva nem. Klasszikus Spring MVC-ben root (service) és servlet (web) context-ek. Spring Boot-ban flat context a jellemző.


9. Szószedet

Fogalom Jelentés
BeanFactory Alapszintű IoC container interfész, lazy bean init
ApplicationContext Teljes funkcionalitású container (BeanFactory + enterprise szolgáltatások)
@Configuration Java-based konfigurációs osztály, CGLIB proxy-val
@ComponentScan Automatikus bean regisztráció csomagok szkennelésével
@PropertySource Külső property fájl betöltése az Environment-be
@Import Több konfigurációs osztály összekapcsolása
@Profile Bean/konfiguráció feltételes aktiválása profil alapján
MessageSource i18n felület, lokalizált üzenetek feloldása
ApplicationEventPublisher Eseményeket publikáló interfész
BeanFactoryPostProcessor Bean definíciók módosítása példányosítás előtt
ContextRefreshedEvent Esemény a context teljes inicializálása után
proxyBeanMethods @Configuration attribútum, CGLIB proxy be/kikapcsolás

10. Gyorsreferencia

BeanFactory           →  Lightweight, lazy init, csak DI
ApplicationContext    →  BeanFactory + AOP + Event + i18n + Environment

Konfigurációs stílusok:
  XML:        ClassPathXmlApplicationContext("beans.xml")
  Java:       AnnotationConfigApplicationContext(AppConfig.class)
  Boot:       SpringApplication.run(MyApp.class, args)

Context lifecycle:
  Def load → BFPP → Instantiate → BPP → @PostConstruct → Ready → Close → @PreDestroy

@Configuration:
  CGLIB proxy → inter-bean ref = singleton
  proxyBeanMethods=false → lite mode, nincs proxy

Gyakori implementációk:
  AnnotationConfigApplicationContext        standalone + Java config
  ClassPathXmlApplicationContext            standalone + XML
  AnnotationConfigServletWebServerAC        Spring Boot web

Context hierarchia:
  child.setParent(parent)
  child → parent bean-ek láthatók
  parent → child bean-ek NEM láthatók

Tipikus hibák:
  ✗ BeanFactory használata ApplicationContext helyett
  ✗ Context bezárás elfelejtése (standalone)
  ✗ Profile beállítás refresh() után
  ✗ Többszöri refresh() meghívás

🎮 Játékok

10 kérdés