> ## Documentation Index
> Fetch the complete documentation index at: https://resources.devweekends.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Spring Boot Quickstart

> Bootstrap your first application and understand the magic

# Spring Boot Quickstart

Spring Boot is an opinionated framework that simplifies the creation of stand-alone, production-grade Spring-based applications. It takes the "convention over configuration" approach.

**Real-world analogy:** Think of plain Spring Framework as buying raw lumber, nails, and blueprints to build a house from scratch. Spring Boot is like buying a prefab home -- the walls are pre-assembled, the plumbing is routed, and the electrical wiring follows code. You can still customize everything, but the 80% of decisions that are the same for every house are already made for you. That is what "opinionated defaults" means in practice.

## 1. The Magic of Spring Initializr

You rarely start a Spring project from scratch. You use the **Spring Initializr**.

1. Go to [start.spring.io](https://start.spring.io/)
2. **Project**: Maven / Gradle (We'll use Maven for this course)
3. **Language**: Java
4. **Spring Boot**: 3.x.x (Latest stable)
5. **Project Metadata**:
   * Group: `com.devweekends`
   * Artifact: `demo`
   * Packaging: `Jar`
   * Java: 17
6. **Dependencies** (Add these):
   * **Spring Web**: For building REST APIs (uses Tomcat as default embedded server).
   * **Spring Boot DevTools**: For fast feedback loops (auto-restart).
   * **Lombok**: To reduce boilerplate code.

Click **GENERATE**, unzip the project, and open it in your IDE (IntelliJ or VS Code).

## 2. Project Structure

```text theme={null}
src/
├── main/
│   ├── java/
│   │   └── com/devweekends/demo/
│   │       └── DemoApplication.java  <-- Entry Point
│   └── resources/
│       ├── application.properties    <-- Configuration
│       ├── static/                   <-- Static assets (JS/CSS)
│       └── templates/                <-- Server-side templates (Thymeleaf)
```

### The Entry Point

```java theme={null}
package com.devweekends.demo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// This single annotation replaces 3 separate annotations (see below).
// SpringApplication.run() bootstraps the IoC container, starts the embedded
// server, and triggers auto-configuration -- all in one line.
@SpringBootApplication
public class DemoApplication {
    public static void main(String[] args) {
        // This returns an ApplicationContext -- the "factory" that holds all your beans.
        // In production, you rarely interact with this directly, but knowing it exists
        // helps you understand how Spring manages your entire object graph.
        SpringApplication.run(DemoApplication.class, args);
    }
}
```

The `@SpringBootApplication` annotation is a convenience annotation that adds all of the following:

* `@Configuration`: Tags the class as a source of bean definitions.
* `@EnableAutoConfiguration`: Tells Spring Boot to start adding beans based on classpath settings (e.g., if `spring-web` is on the classpath, setup Tomcat).
* `@ComponentScan`: Tells Spring to look for other components, configurations, and services in the `com/devweekends/demo` package.

## 3. Your First REST Controller

Create a new file `HelloController.java` next to `DemoApplication.java`.

```java theme={null}
package com.devweekends.demo;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/hello")
    public String sayHello() {
        return "Hello, Dev Weekends!";
    }
}
```

* `@RestController`: Marks this class as a request handler where every method returns a domain object directly (JSON/XML) instead of a view.
* `@GetMapping("/hello")`: Maps HTTP GET requests to `/hello` to the `sayHello()` method.

## 4. Running the Application

In your terminal (or IDE):

```bash theme={null}
./mvnw spring-boot:run
```

You should see logs starting with the Spring banner. Look for:
`Tomcat started on port(s): 8080 (http)`

Open `http://localhost:8080/hello` in your browser. You should see "Hello, Dev Weekends!".

## 5. Dependency Injection (DI) Basics

Spring's core is the **Application Context** (the IoC container). It manages the lifecycle of your objects (Beans).

**The Factory Analogy:** Imagine a car assembly plant (the IoC container). Instead of each worker going out to buy their own screws, engines, and tires, the factory maintains a warehouse of parts (beans) and delivers exactly what each workstation needs. The workers (your classes) declare what they need ("I need an engine"), and the factory (Spring) delivers it. This is **Inversion of Control** -- your code does not create its own dependencies; the container "inverts" that responsibility and hands them to you.

Instead of `new Service()`, you ask Spring to give you an instance.

```java theme={null}
@Service // 1. Register this class as a Bean (tells Spring: "put this in the warehouse")
public class GreetingService {
    public String getGreeting() {
        return "Welcome to Spring Boot Mastery";
    }
}

@RestController
public class HelloController {

    // 'final' ensures immutability -- once Spring injects the service, it cannot be swapped.
    // This is a deliberate design choice: your controller's dependencies are fixed at construction time.
    private final GreetingService greetingService;

    // 2. Constructor Injection (Recommended)
    // Spring sees this constructor, checks its warehouse for a GreetingService bean,
    // and passes it in automatically. No @Autowired needed when there's only one constructor.
    public HelloController(GreetingService greetingService) {
        this.greetingService = greetingService;
    }

    @GetMapping("/greet")
    public String greet() {
        return greetingService.getGreeting();
    }
}
```

This makes your code testable and loosely coupled. In a unit test, you can simply write `new HelloController(mockGreetingService)` -- no Spring context needed.

## 6. Spring Boot Internals: How it Works

Many developers use `@SpringBootApplication` without knowing what it does. It's a compound annotation:

1. **`@SpringBootConfiguration`**: Just a specialized `@Configuration`.
2. **`@ComponentScan`**: Scans the current package and sub-packages for Components.
3. **`@EnableAutoConfiguration`**: **The Magic**.

### How Auto-Configuration Works

Spring Boot looks at the classpath and makes intelligent decisions based on what it finds -- like a smart home system that detects which appliances are plugged in and configures itself accordingly.

* Is `spring-webmvc` on the classpath? -> **Configure DispatcherServlet** and embedded Tomcat.
* Is `h2` on the classpath? -> **Configure DataSource** with an in-memory database.
* Is `hibernate-core` on the classpath? -> **Configure EntityManagerFactory** with sensible defaults.

It uses `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports` to find configuration classes and applies them conditionally (`@ConditionalOnClass`, `@ConditionalOnMissingBean`).

**Production tip:** Auto-configuration is powerful but can surprise you. If Spring configures something you did not expect, add `--debug` to your startup args or set `debug=true` in `application.properties`. This prints a detailed **Conditions Evaluation Report** showing every auto-configuration class that was matched or skipped, and why. This is your go-to diagnostic tool when Spring "magically" does something you did not ask for.

<div className="flex justify-center my-4">
  <div className="w-full max-w-3xl">
    ```mermaid theme={null}
    graph TD
        A[Start App] --> B[Read classpath]
        B --> C{DispatcherServlet found?}
        C -- Yes --> D[Configure Tomcat & Spring MVC]
        C -- No --> E[Skip Web Config]
        D --> F{DataSource found?}
        F -- Yes --> G[Configure JDBC Connection]
        F -- No --> H[Skip DB Config]
        G --> I[Application Ready]
    ```
  </div>
</div>

## 7. Bean Scopes & Lifecycle

By default, all beans are **Singletons** (created once per app). But you can change this.

### Scopes

* **Singleton (Default)**: One instance per container. Think of it as a shared office printer -- everyone uses the same one.
* **Prototype**: A new instance *every single time* it is requested. Like disposable coffee cups -- fresh one per use.
* **Request**: One instance per HTTP Request. Like a shopping cart that exists only for the duration of a single API call.
* **Session**: One instance per HTTP Session. Like a user's browser tab state -- persists across multiple requests from the same session.

**Production pitfall:** Injecting a Prototype-scoped bean into a Singleton creates a subtle bug. The Singleton is created once, so it gets one Prototype instance and holds onto it forever -- defeating the purpose. If you need a fresh Prototype each time, inject an `ObjectFactory<T>` or `Provider<T>` instead, and call `.getObject()` / `.get()` when you need a new instance.

```java theme={null}
@Component
@Scope("prototype")
public class UserAction {
    // New instance created every time
}
```

### Lifecycle Callbacks

Sometimes you need to run logic right after a bean is created (e.g., open a socket) or before it dies (e.g., close file).

```java theme={null}
@Component
public class DatabaseConnection {

    @PostConstruct
    public void init() {
        System.out.println("Bean created! Opening connection...");
    }

    @PreDestroy
    public void cleanup() {
        System.out.println("App shutting down! Closing connection...");
    }
}
```

## 8. Type-Safe Configuration

Stop using `@Value("${my.config}")` for anything beyond trivial cases. Scattered `@Value` annotations are the configuration equivalent of magic numbers -- hard to find, impossible to validate at startup, and easy to typo. Instead, group related properties into a POJO.

**application.yml**

```yaml theme={null}
app:
  mail:
    host: smtp.gmail.com
    port: 587
    enabled: true
```

**Java Config Class**

```java theme={null}
// Spring maps 'app.mail.host' -> host, 'app.mail.port' -> port automatically.
// Using a record gives you immutability for free -- config values cannot be
// accidentally mutated at runtime.
@ConfigurationProperties(prefix = "app.mail")
public record MailConfig(String host, int port, boolean enabled) {}
```

**Enable it in Main Class**

```java theme={null}
@SpringBootApplication
@EnableConfigurationProperties(MailConfig.class)
public class DemoApplication {}
```

Now you can inject `MailConfig` anywhere. The major advantage: Spring validates the entire config block at startup. If `app.mail.port` is missing or cannot be parsed as an integer, the application fails fast with a clear error message instead of crashing at 3 AM when the code path is first hit.

**Production tip:** Add `@Validated` and Jakarta validation annotations to your config class for even stricter startup checks:

```java theme={null}
@Validated
@ConfigurationProperties(prefix = "app.mail")
public record MailConfig(
    @NotBlank String host,
    @Min(1) @Max(65535) int port,
    boolean enabled
) {}
```

***

## 9. Deep Dive: The IoC Container

The **Inversion of Control (IoC)** container is the heart of Spring. It manages the lifecycle of your objects (Beans).

### BeanFactory vs ApplicationContext

* **BeanFactory**: The root interface. Provides basic features (DI). Lazy loading.
* **ApplicationContext**: A sub-interface. Adds enterprise specific functionality:
  * Internationalization (i18n).
  * Event publishing.
  * Web application support.
  * **Eager loading** (instantiates singletons on startup), which is better for detecting errors early.

> In Spring Boot, `SpringApplication.run()` returns an `ApplicationContext`.

## 10. Dependency Injection Patterns

How should you inject dependencies?

### 1. Field Injection (Avoid)

```java theme={null}
@Autowired
private UserService userService;
```

* **Pros:** Concise.
* **Cons:** Hides dependencies. Impossible to unit test without reflection/mocks. Creates circular dependency risks.

### 2. Setter Injection (Optional Deps)

```java theme={null}
@Autowired
public void setUserService(UserService userService) {
    this.userService = userService;
}
```

* **Pros:** Allows optional dependencies (can re-configure later).
* **Cons:** Bean is not immutable.

### 3. Constructor Injection (Recommended)

```java theme={null}
private final UserService userService;

public UserController(UserService userService) {
    this.userService = userService;
}
```

* **Pros:**
  * **Immutability:** Fields can be `final`.
  * **Testability:** Just pass mocks in `new UserController(mockService)`.
  * **Safety:** Object is fully initialized before use.
  * **Circular Dependency Detection:** Fails fast at startup if A -> B -> A.

### multiple Implementations? Use @Qualifier or @Primary

If you have `SmsNotificationService` and `EmailNotificationService` implementing `NotificationService`, Spring gets confused.

* **`@Primary`**: The default choice.
* **`@Qualifier("sms")`**: Specific choice injecting time.

```java theme={null}
public class CheckoutService {
    public CheckoutService(@Qualifier("sms") NotificationService sender) { ... }
}
```

## 11. Advanced Bean Lifecycle

It's not just "Create -> Use -> Destroy".

```mermaid theme={null}
graph TD
    A[Instantiate] --> B[Populate Properties]
    B --> C[BeanNameAware / BeanFactoryAware]
    C --> D[BeanPostProcessor: postProcessBeforeInitialization]
    D --> E[@PostConstruct / init-method]
    E --> F[BeanPostProcessor: postProcessAfterInitialization]
    F --> G[Ready to Use]
    G --> H[@PreDestroy / destroy-method]
    H --> I[Destroyed]
```

### BeanPostProcessors (BPP)

These are hooks that allow you to modify beans *before* they are fully initialized.
**Example:** How `@Transactional` works.
Spring has a BPP that scans for `@Transactional`. If found, it wraps your bean in a **Proxy** (CGLIB or JDK Dynamic Proxy) before handing it to the container. The container never holds your actual class, only the Proxy!

***

## Interview Deep-Dive

<AccordionGroup>
  <Accordion title="Explain the difference between BeanFactory and ApplicationContext. When would you ever use BeanFactory directly?">
    **Strong Answer:**

    * `BeanFactory` is the root IoC container interface. It provides the core DI mechanism: bean instantiation, wiring, and lifecycle management. Critically, it uses lazy initialization -- beans are not created until they are first requested via `getBean()`. This means startup is fast, but you will not discover configuration errors (missing dependencies, circular references) until runtime when that code path is actually hit.
    * `ApplicationContext` extends `BeanFactory` and adds enterprise features: event publishing (`ApplicationEventPublisher`), internationalization (`MessageSource`), environment abstraction, and -- most importantly for production -- eager initialization of singleton beans. This means all your `@Service`, `@Repository`, and `@Controller` beans are created at startup. If you have a typo in a `@Qualifier` or a missing dependency, the app fails to start rather than failing at 2 AM when a rarely-used code path executes.
    * In practice, you almost never use `BeanFactory` directly. The one legitimate use case is in extremely memory-constrained environments (embedded systems, certain Android scenarios) where you cannot afford to eagerly instantiate hundreds of beans. Spring Boot always uses `ApplicationContext` -- specifically `AnnotationConfigServletWebServerApplicationContext` for servlet-based web apps and `AnnotationConfigReactiveWebServerApplicationContext` for WebFlux apps.
    * The gotcha that catches people: even within an `ApplicationContext`, prototype-scoped beans are still lazy. The container creates them on demand and does not manage their full lifecycle (no `@PreDestroy` callback for prototypes). This is a common source of resource leaks.

    **Follow-up: If ApplicationContext eagerly initializes all singletons, how do you make a specific bean lazy without switching the entire container to BeanFactory?**

    Use `@Lazy` on the bean definition or on the injection point. When placed on a `@Component` class, Spring defers creation until first access. When placed on a constructor parameter (`@Lazy UserService userService`), Spring injects a proxy that triggers real initialization on first method call. This is useful for breaking circular dependencies or deferring expensive initialization (like a bean that opens a connection pool to a rarely-used legacy database). But be careful: `@Lazy` on an injection point means your startup validation no longer covers that dependency chain. If the lazy bean has a misconfiguration, you will only discover it at runtime.
  </Accordion>

  <Accordion title="Why does Spring recommend constructor injection over field injection? Go beyond the testing argument -- what are the deeper implications?">
    **Strong Answer:**

    * The testing argument is the one everyone knows: with constructor injection, you can write `new OrderService(mockRepo, mockClient)` in a unit test without any Spring context or reflection hacks. With field injection (`@Autowired private OrderRepository repo`), you need Mockito's `@InjectMocks` or Spring's test context, both of which are slower and more fragile.
    * But the deeper reason is about invariant enforcement. Constructor injection lets you declare fields as `final`, which means the dependency graph of a bean is immutable after construction. The object is either fully initialized or it does not exist. With field injection, there is a window between object construction and field population where the object exists in an invalid state -- all `@Autowired` fields are null. If any initialization code in `@PostConstruct` or in the constructor itself tries to use those fields, you get a `NullPointerException`.
    * Constructor injection also makes circular dependencies fail fast. If Service A needs Service B in its constructor, and Service B needs Service A in its constructor, Spring cannot create either and throws `BeanCurrentlyInCreationException` at startup. With field injection, Spring can create both objects (fields are null), then populate fields via reflection, silently hiding the circular dependency. That circular dependency is still a design problem -- you just do not discover it until it causes subtle ordering bugs in production.
    * There is also a design pressure benefit: if your constructor has 12 parameters, that is a code smell screaming "this class has too many responsibilities." Field injection hides this because adding `@Autowired private AnotherService x` is one silent line. Constructor injection forces you to confront it.

    **Follow-up: You inherit a codebase with field injection everywhere. What is your migration strategy?**

    I would not do a big-bang rewrite. Instead, I would set a team convention: all new code uses constructor injection, and when you touch an existing class for a feature change, you migrate that class. Use Lombok's `@RequiredArgsConstructor` to keep it concise -- make all injected fields `private final`, add the annotation, and delete the `@Autowired` field annotations. Run the tests after each class migration to catch any circular dependency that was previously hidden. Over 2-3 months, the hot paths are migrated organically. For an automated approach, tools like OpenRewrite have recipes that can do this refactoring across an entire codebase in one PR, but I would still review the diff carefully for circular dependency breakage.
  </Accordion>

  <Accordion title="A junior developer writes a Prototype-scoped bean and injects it into a Singleton service. They expect a fresh instance per request, but it does not work. Explain what went wrong at the container level and how to fix it.">
    **Strong Answer:**

    * Here is what happens internally: Spring creates the singleton `OrderService` once during startup. During construction, it resolves all dependencies, including the prototype-scoped `ShoppingCart`. Spring creates one `ShoppingCart` instance and injects it. From this point forward, `OrderService` holds a direct reference to that single `ShoppingCart` instance. When another request comes in, `OrderService` is already fully constructed -- Spring does not re-inject its fields. The prototype scope promise ("new instance every time it is requested from the container") is honored, but nobody is requesting it from the container again. The singleton just uses its stale reference.
    * Fix 1: Inject `ObjectFactory<ShoppingCart>` or `Provider<ShoppingCart>` (from `jakarta.inject`). Each time you call `provider.get()`, Spring goes back to the container and creates a fresh prototype instance. This is the cleanest approach for most use cases.
    * Fix 2: Use `@Lookup` method injection. Declare an abstract method or a method that Spring will override at runtime via CGLIB to return a fresh prototype instance. Less common in modern code but still valid.
    * Fix 3: Inject `ApplicationContext` directly and call `context.getBean(ShoppingCart.class)`. This works but is the Service Locator anti-pattern -- it couples your code to the Spring API and makes testing harder.
    * Fix 4: For web applications specifically, use `@Scope(value = "request", proxyMode = ScopedProxyMode.TARGET_CLASS)` instead of prototype. This creates a CGLIB proxy that delegates to a request-scoped instance. The singleton holds the proxy, and each HTTP request gets its own real instance behind the proxy. This is typically what people actually want when they think "prototype per request."

    **Follow-up: What happens to the lifecycle callbacks (@PreDestroy) of prototype-scoped beans?**

    This is the part most people miss: Spring does not manage the complete lifecycle of prototype beans. The container creates and configures the prototype bean (including calling `@PostConstruct`), hands it off, and then forgets about it. `@PreDestroy` is never called by the container for prototype beans because the container does not track them after creation. If your prototype bean holds a resource (a file handle, a socket, a database connection), you are responsible for closing it yourself. This is documented but rarely read, and it leads to resource leaks in production. If you need lifecycle management for short-lived beans, consider request scope with a proxy -- Spring does manage the full lifecycle for request-scoped beans.
  </Accordion>

  <Accordion title="Explain how Spring Boot auto-configuration actually works. Specifically, what role do @Conditional annotations play, and how would you write a custom auto-configuration for an internal library?">
    **Strong Answer:**

    * Auto-configuration is not magic -- it is conditional bean registration at scale. Spring Boot ships with hundreds of `@Configuration` classes (like `DataSourceAutoConfiguration`, `WebMvcAutoConfiguration`), each registered in `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports`. At startup, Spring loads all of these classes and evaluates their conditions.
    * The `@Conditional` family is the gating mechanism. `@ConditionalOnClass(DataSource.class)` checks if that class exists on the classpath (without loading it). `@ConditionalOnMissingBean(DataSource.class)` checks if the user has already defined their own `DataSource` bean. `@ConditionalOnProperty(name = "app.feature.enabled", havingValue = "true")` checks a configuration property. These compose: a configuration class might require all three conditions to be true before its beans are registered.
    * The evaluation order matters and is controlled by `@AutoConfigureOrder`, `@AutoConfigureBefore`, and `@AutoConfigureAfter`. For example, `DataSourceAutoConfiguration` must run before `JpaRepositoriesAutoConfiguration` because JPA needs a DataSource bean to already exist.
    * To write a custom auto-configuration for an internal library: (1) Create a `@Configuration` class with `@ConditionalOnClass` for your library's key class. (2) Define beans with `@ConditionalOnMissingBean` so users can override them. (3) Use `@ConfigurationProperties` for externalized defaults. (4) Register it in `META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports` in your library's JAR. (5) Crucially, put the configuration in a separate Maven module from the library itself -- the `autoconfigure` module depends on the library, and the `starter` module depends on both. This is the same structure Spring Boot itself uses.

    **Follow-up: A team member's auto-configuration is silently not being applied. How do you debug it?**

    First, enable the Conditions Evaluation Report by setting `debug=true` in application.properties or passing `--debug` at startup. The report will list every auto-configuration class under "Positive matches" (applied) or "Negative matches" (skipped) with the exact condition that failed. Common failures: the class referenced in `@ConditionalOnClass` is not on the classpath (missing dependency), a `@ConditionalOnMissingBean` matched because another configuration already defined that bean type, or the imports file has a typo in the fully qualified class name. Also check the `@AutoConfigureAfter` ordering -- if your auto-config depends on another that has not run yet, the `@ConditionalOnBean` check might fail because the bean it is looking for does not exist yet at that point in the configuration phase.
  </Accordion>

  <Accordion title="Describe the full lifecycle of a Spring Bean from instantiation to destruction. Where exactly do BeanPostProcessors fit in, and why does that matter for understanding @Transactional and @Async?">
    **Strong Answer:**

    * The lifecycle has distinct phases. First, Spring instantiates the bean via the constructor (this is where constructor injection happens). Second, it populates properties (setter injection, `@Value` resolution). Third, it calls Aware interfaces (`BeanNameAware`, `BeanFactoryAware`, `ApplicationContextAware`) so the bean can learn about its environment. Fourth -- and this is the critical phase -- it runs `BeanPostProcessor.postProcessBeforeInitialization()` on every registered BPP. Fifth, it calls initialization callbacks (`@PostConstruct`, `InitializingBean.afterPropertiesSet()`, custom `init-method`). Sixth, it runs `BeanPostProcessor.postProcessAfterInitialization()`. Seventh, the bean is ready for use. On shutdown, it calls `@PreDestroy`, `DisposableBean.destroy()`, and custom `destroy-method`.
    * The `postProcessAfterInitialization` phase is where the proxy wrapping happens. `AnnotationAwareAspectJAutoProxyCreator` (a BPP) inspects every bean after initialization. If the bean or any of its methods are annotated with `@Transactional`, `@Async`, `@Cacheable`, or matched by any AOP pointcut, the BPP replaces the original bean instance with a CGLIB proxy (or JDK dynamic proxy if it implements an interface). The ApplicationContext then stores the proxy, not your original object.
    * This is why self-invocation breaks `@Transactional`. When your method calls `this.otherMethod()`, `this` is the raw target object inside the proxy, not the proxy itself. The call bypasses the proxy's transaction interceptor entirely. The transaction advice is a method interceptor on the proxy -- if you do not go through the proxy, the advice never fires.
    * This also explains why `@Transactional` on a `private` method has no effect. CGLIB creates a subclass of your bean, and it cannot override private methods. The proxy method just calls `super.yourMethod()` without wrapping it in transaction logic. Spring does not warn you about this by default -- your `@Transactional(readOnly = true)` on a private helper method is silently ignored.

    **Follow-up: How would you detect at runtime whether the bean you are holding is a proxy or the actual target?**

    You can check with `AopUtils.isAopProxy(bean)`, `AopUtils.isCglibProxy(bean)`, or `AopUtils.isJdkDynamicProxy(bean)`. To get the underlying target from a proxy, use `AopProxyUtils.getSingletonTarget(bean)` or cast to `Advised` and call `getTargetSource().getTarget()`. In debugging, a quick way to tell is that a CGLIB proxy's `getClass().getName()` will contain `$$SpringCGLIB$$` in it. If you are debugging why a `@Transactional` annotation is not being honored, the first thing to check is whether the bean injected into the caller is actually a proxy. If it is not, the BPP did not wrap it, which means either the annotation is on a private method, or the class is being instantiated manually with `new` instead of being managed by the container.
  </Accordion>
</AccordionGroup>
