Spring Basics - Quick Interview Notes (Crash Course)
Table of Content
- 1. Overview of Spring
- 2. Inversion of Control (IoC)
- 2.1 Different Ways to Declare Bean Obejcts in Spring
- 2.2 Spring's Bean Container: BeanFactory
- 2.3 The Bean Lifecycle in Spring
- 2.4 Bean Injection Methods in Spring
- 3. Event Listeners in Spring
- 4. Aspect-Oriented Programming (AOP) in Spring
- 4.1 Introduction to AOP
- 4.2 Static Proxy vs. Dynamic Proxy
- 4.3 Implementing AOP in Spring
- 4.4 Declaring Pointcuts
- References
1. Overview of Spring
The primary goal of the Spring framework is to simplify enterprise application development in Java EE.
Spring offers two core features:
- Inversion of Control (IoC): Also known as Dependency Injection (DI)
- Aspect-Oriented Programming (AOP)
2. Inversion of Control (IoC)
Inversion of Control (IoC) refers to delegating the control and management of objects to the Spring framework instead of handling it manually. In practice, this means that when you need an object (known as a Bean, such as a business logic handler or a connection pool), you don’t need to create it yourself using new
. Instead, you retrieve it directly from the Spring container. How these objects are initialized can either be defined by the developer or left to Spring’s default mechanisms.
Dependency Injection (DI) is another name for the IoC feature. It allows Spring to inject the required objects directly into your code, so you don’t need to explicitly acquire them. In practice, this is achieved by annotating the variable with @Autowired
.
2.1 Different Ways to Declare Bean Obejcts in Spring
To perform dependency injection of a bean object, you first need to declare the bean, which tells Spring how to initialize it.
There are several ways to declare beans in Spring:
(1) XML Configuration:Declaring objects through the <bean>
element in the XML configuration file. (This method is mostly deprecated after the advent of Spring Boot)
```xml <bean id="myBean" class="com.example.MyBean"/> ```
(2) Annotation-Based Configuration:Using annotations to mark classes, instructing Spring to manage them as beans at runtime. Common annotations include @Component
、@Service
、@Repository
and @Controller
.
```java @Component public class MyBean { ... } ```
@Component
:The most generic annotation used to mark any class as a Spring bean, such as utility classes or classes that don't have a clear category.@Repository
:Typically used to mark classes in the data access layer (DAO).@Service
:Typically used to mark classes in the business logic layer (Service).@Controller
:Typically used to mark controller classes in the controller layer (e.g., in Spring MVC).
The reason for these different annotation names: ① (Main reason) Semantic distinction; ② Spring performs special handling for some annotations. For example,
@Repository
translates underlying data access exceptions into Spring'sDataAccessException
(3) JavaConfig Configuration:Configuring Spring beans through Java classes. You can mark a configuration class with the @Configuration
annotation and declare beans in methods using the @Bean
annotation.
```java @Configuration public class AppConfig { @Bean public MyBean myBean() { return new MyBean(); } // Multiple beans can be configured. Typically, related beans are grouped under one config class. } ```
For the
@Bean
configuration method, you need to enable scanning using the@ComponentScan
annotation so that Spring can manage the beans. For example: Adding@ComponentScan("com.example")
to the main class.
2.2 Spring's Bean Container: BeanFactory
After Spring initializes the Beans, a container is needed to store these Beans. This container is the BeanFactory
.
BeanFactory
is an interface that defines several important getBean(...)
methods, allowing users to easily retrieve Bean objects using different methods, such as by name or class type.
In Spring Boot web applications, the default implementation of BeanFactory
used is AnnotationConfigServletWebServerApplicationContext
. Its inheritance hierarchy is shown in the diagram below:
From top to bottom, the most important classes/interfaces are as follows:
- BeanFactory:The most basic container interface, providing the fundamental Inversion of Control (IoC) functionality.
- ApplicationContext:A subinterface of BeanFactory, which extends its functionality and offers a more complete set of features, including internationalization, event propagation, resource access, AOP support, and more.
- WebApplicationContext:A specific interface for web applications, built on top of ApplicationContext. It adds features tailored for web development, such as managing the lifecycle of Servlet contexts, accessing Servlet properties, and registering Servlets and Filters in web applications.
- ConfigurableWebApplicationContext: A subinterface of WebApplicationContext, offering additional configuration and customization capabilities.
- ServletWebServerApplicationContext:A specific implementation class of ApplicationContext for web applications. It integrates with the Servlet container (e.g., Tomcat), responsible for configuring and starting the Servlet container, and provides Servlet-container-specific functionalities like setting context paths, configuring SSL, and handling error pages.
- AnnotationConfigServletWebServerApplicationContext:A subclass of ServletWebServerApplicationContext, which uses annotation-based configuration to manage the Beans in a web application. It scans specified packages (using the
@ComponentScan
annotation) to find and register Beans with specific annotations, then assembles them into the container.
In non-Spring Boot or non-web applications, other implementations of BeanFactory are also used, such as
XmlBeanFactory
,FileSystemXmlApplicationContext
,ClassPathXmlApplicationContext
, etc.
2.3 The Bean Lifecycle in Spring
A Spring Bean goes through three main stages from creation to destruction:
- Instantiation:When the container starts, Spring will instantiate the Bean based on the configuration (via XML, annotations, etc.), which means invoking the Bean’s constructor.
- Dependency Injection:After instantiation, if the Bean has dependencies on other Beans, those Beans will be injected because they may be needed in the subsequent initialization process.
- Initialization:The user-defined initialization method is executed. There are several ways to define this:
- Implement the
InitializingBean
interface and theafterPropertiesSet()
method - Use the
@PostConstruct
annotation on the Bean's initialization method. - Specify an initialization method in the
@Bean
annotation.
- Implement the
- In Use:After initialization, the Bean is stored in the Bean container, and can be retrieved and used during runtime.
- Destruction:The destruction phase occurs when the Bean is no longer needed (usually when the program exits normally). Spring provides two ways to define a destruction method:
- Implement the
DisposableBean
interface and thedestroy()
method. - Use the
@PreDestroy
annotation on the Bean's destruction method.
- Implement the
Example 1 (Using Annotations for the Bean Lifecycle with @Component
):
```java @Component public class MyBean1 { @Autowired private RestTemplate restTemplate; public MyBean1() { System.out.println("Construct MyBean1. restTemplate:" + restTemplate); // restTemplate is null } @PostConstruct // post construct public void init() { System.out.println("Init MyBean1. restTemplate:" + restTemplate); // restTemplate has been injected. } @PreDestroy // pre destroy(在销毁之前) public void destroy() { System.out.println("Destroy MyBean1"); } } ```
``` // Start spring Boot application ... Construct MyBean1. restTemplate:null Init MyBean1. restTemplate:org.springframework.web.client.RestTemplate@5effc15d // Shut down SpringBoot application... Destroy MyBean1 ```
Example 2 (Using Interfaces for the Bean Lifecycle with @Component
):
```java @Component public class MyBean2 implements InitializingBean, DisposableBean { @Autowired private RestTemplate restTemplate; public MyBean2() { System.out.println("Construct MyBean2. restTemplate:" + restTemplate); // restTemplate is null } @Override public void afterPropertiesSet() throws Exception { System.out.println("Init MyBean2. restTemplate:" + restTemplate); // restTemplate has been injected. } @Override public void destroy() { System.out.println("Destroy MyBean2"); } } ```
``` // Start spring boot application ... Construct MyBean2. restTemplate:null Init MyBean2. restTemplate:org.springframework.web.client.RestTemplate@5effc15d // Shut down spring boot application ... Destroy MyBean2 ```
Example 3(Use @Bean
):
```java class MyBean3 { @Autowired public RestTemplate restTemplate; public MyBean3() { System.out.println("Construct MyBean3. restTemplate:" + restTemplate); // restTemplate为null } private void init() { System.out.println("Init MyBean3. restTemplate:" + restTemplate); // restTemplate has been injected. } private void destroy() { System.out.println("Destroy MyBean3"); } } @Configuration public class MyBeanConfiguration { @Bean(initMethod="init", destroyMethod="destroy") public MyBean3 myBean() { return new MyBean3(); } } ```
``` // Start Spring boot application ... Construct MyBean3. restTemplate:null Init MyBean3. restTemplate:org.springframework.web.client.RestTemplate@5effc15d // Shut down spring boot application... Distroy MyBean3 ```
When it comes to the Bean lifecycle, most people have probably seen this diagram online:
This diagram essentially combines the methods mentioned above and complicates the understanding. However, developers don't need to worry about the order in which these methods are executed, and typically, they won't use all of them together.
2.4 Bean Injection Methods in Spring
Once we have declared the Beans, we can inject them wherever they are needed. Spring provides the following injection methods:
Suppose we have a configuration class that defines the following Beans:
```java @Configuration public class TestConfiguration { @Bean(name = "restTemplate1") // There are two RestTemplate Beans with different names public RestTemplate restTemplate1() { return new RestTemplate(); } @Bean(name = "restTemplate2") public RestTemplate restTemplate2() { return new RestTemplate(); } @Bean // This is a Random Bean. public Random random() { return new Random(); } } ```
(1) Injection using Annotations: This method allows for dependency injection using annotations in the code, such as @Autowired
, @Resource
, etc.
@Autowired
:This annotation, provided by Spring, automatically injects dependencies based on the type. If you need to inject by name, you can use it in conjunction with the@Qualifier
annotation.@Resource
:This annotation, provided by Java EE, allows you to specify whether to inject by name or by type through its parameters.
```java @Component public class MyBean1 {
@Autowired // Find a unique Bean with the Random class.
private Random random1;
@Resource(type = Random.class) // Injection by the class type.
private Random random2;
// @Autowired // This injection will cause error because there are two Beans with the same class type "RestTemplate".
// private RestTemplate restTemplate;
@Autowired
@Qualifier("restTemplate1") // Injection by the bean name.
private RestTemplate restTemplate1;
@Resource(name = "restTemplate2") // Injection by the bean name.
private RestTemplate restTemplate2;
@PostConstruct
public void init() {
System.out.println("random1:" + random1);
System.out.println("random2:" + random2);
System.out.println("restTemplate1:" + restTemplate1);
System.out.println("restTemplate2:" + restTemplate2);
}
}
``` (2) **Constructor-based Injection**:You can directly specify the Beans that need to be injected in the constructor of the class. ```java @Component public class MyBean1 { private Random random1; private Random random2; private RestTemplate restTemplate1; private RestTemplate restTemplate2; private MyBean1(Random random1, Random random2, // Specify the name of the bean to be injected using @Qualifier @Qualifier("restTemplate1") RestTemplate restTemplate1, // This can be injected normally and unexpectedly. I don't know why. My version is spring-beans5.3.9 RestTemplate restTemplate2 ) { this.random1 = random1; this.random2 = random2; this.restTemplate1 = restTemplate1; this.restTemplate2 = restTemplate2; } @PostConstruct public void init() { System.out.println("random1:" + random1); System.out.println("random2:" + random2); System.out.println("restTemplate1:" + restTemplate1); System.out.println("restTemplate2:" + restTemplate2); } } ```
``` random1:java.util.Random@738a1324 random2:java.util.Random@738a1324 // Since there is only a Random bean, they are the same. restTemplate1:org.springframework.web.client.RestTemplate@65a86de0 // restTemplate1 restTemplate2:org.springframework.web.client.RestTemplate@745e1fb7 // restTemplate2 ```
(3) Injection using Aware Interfaces:Spring provides several XxxxxAware
interfaces that allow you to inject system Beans like ApplicationContext
or BeanFactory
. (Although you can also use @Autowired for this purpose.)
```java @Component public class MyBean1 implements ApplicationContextAware, ResourceLoaderAware { private ApplicationContext applicationContext; private ResourceLoader resourceLoader; @Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } @Override public void setResourceLoader(ResourceLoader resourceLoader) { this.resourceLoader = resourceLoader; } @Autowired // You can use @Autowired to inject it. private ApplicationContext applicationContext2; @Autowired private ResourceLoader resourceLoader2; @PostConstruct public void init() { System.out.println("applicationContext: " + applicationContext); System.out.println("resourceLoader: " + resourceLoader); System.out.println("applicationContext2: " + applicationContext2); System.out.println("resourceLoader2: " + resourceLoader2); } } ```
``` // These beans is the same, because they are the same implement class in Spring boot web application. applicationContext: ... AnnotationConfigServletWebServerApplicationContext@1dc76fa1 ... resourceLoader: ... AnnotationConfigServletWebServerApplicationContext@1dc76fa1 ... applicationContext2: ... AnnotationConfigServletWebServerApplicationContext@1dc76fa1 ... resourceLoader2: ... AnnotationConfigServletWebServerApplicationContext@1dc76fa1 ... ```
3. Event Listeners in Spring
The Spring framework provides a robust event-driven mechanism based on the Observer pattern, enabling event publishing and listening capabilities.
An event listener in Spring is composed of three main parts:
- Event:This represents the message in the Observer pattern. Events are published by event publishers and listened to by event listeners.
- Event Publisher:This corresponds to the subject (observable) in the Observer pattern. In Spring, events are typically published when there are changes in the application context's state. Developers can also define and publish custom events.
- Event Listener:This is equivalent to the observer in the Observer pattern. It is usually implemented by the developer to listen for specific events, such as context state changes in Spring.
To create a custom event listener, simply implement the ApplicationListener<E extends ApplicationEvent>
interface, where the generic type E
specifies the type of event you want to handle. For example:
```java @Component public class MyListener implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { System.out.println("onApplicationEvent:" + event.getSource()); } } ```
3.1 Built-in Event Listeners in Spring
Spring includes many built-in event listeners that respond to various changes in the application context or other system states. If you register a listener for these events, you can hook into the framework’s lifecycle and execute custom logic.
Think of these listeners as Spring's equivalent of lifecycle hooks.
Here are some common built-in events provided by Spring (handled via the ApplicationListener
class):
- ContextRefreshedEvent:Triggered when the
ApplicationContext
is initialized or refreshed. This is often used for tasks like initializing the application or loading caches. - ContextStartedEvent:Triggered when the
ApplicationContext
starts. You can use this event to execute tasks that need to run when the application begins. - ContextStoppedEvent:Triggered when the
ApplicationContext
stops. It is useful for cleanup tasks or releasing resources. - ContextClosedEvent:Triggered when the
ApplicationContext
is closed. This event is typically used for final cleanup and resource release. - RequestHandledEvent:Triggered in Spring MVC after an HTTP request has been processed. It is often used to collect statistics or log request-handling details.
Additionally, other Spring frameworks (such as Spring Boot) offer other types of listeners, such as:
- ServletContextListener:Monitors the lifecycle of the
ServletContext
. - HttpSessionListener:Monitors the lifecycle of HTTP sessions.
- ServletRequestListener:Monitors the lifecycle of HTTP requests, such as request creation and destruction.
- SpringApplicationRunListener:Observes lifecycle events during a Spring Boot application’s startup process.
Example 1(ApplicationListener
):
```java @Component public class MyListener1 implements ApplicationListener<ContextRefreshedEvent> { @Override public void onApplicationEvent(ContextRefreshedEvent event) { System.out.println("ContextRefreshedEvent"); } } ```
```java @Component public class MyListener2 implements ApplicationListener<ContextClosedEvent> { @Override public void onApplicationEvent(ContextClosedEvent event) { System.out.println("ContextClosedEvent"); } } ```
```java @Component public class MyListener3 implements ApplicationListener<ContextStartedEvent> { @Override public void onApplicationEvent(ContextStartedEvent event) { System.out.println("ContextStartedEvent"); } } ```
输出:
``` ContextRefreshedEvent ... ContextRefreshedEvent // After shutting down the application. ContextClosedEvent ```
Different Spring containers might have different events. For example, in my Spring Boot application,
ContextStartedEvent
andContextStoppedEvent
will never triggered. You should useApplicationStartedEvent
andApplicationStoppedEvent
.
Example 2(SpringApplicationRunListener
):
```java public class MySpringBootListener implements SpringApplicationRunListener { // The constructor must be written this way. public MySpringBootListener(SpringApplication application, String[] args) { System.out.println("SpringApplicationRunListener constructor"); } @Override public void starting(ConfigurableBootstrapContext bootstrapContext) { System.out.println("SpringApplicationRunListener starting:" + bootstrapContext); } @Override public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) { System.out.println("SpringApplicationRunListener environmentPrepared:" + bootstrapContext); } @Override public void contextPrepared(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener contextPrepared:" + context); } @Override public void contextLoaded(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener contextLoaded:" + context); } @Override public void started(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener started:" + context); } @Override public void running(ConfigurableApplicationContext context) { System.out.println("SpringApplicationRunListener running:" + context); } @Override public void failed(ConfigurableApplicationContext context, Throwable exception) { System.out.println("SpringApplicationRunListener failed:" + context); } } ```
Add a configuration in src/resource/META-INF/spring.factories
to register the Listener:
``` org.springframework.boot.SpringApplicationRunListener=com.example.MySpringBootListener ```
Output:
``` SpringApplicationRunListener constructor SpringApplicationRunListener starting:org.springframework.boot.DefaultBootstrapContext@2a898881 SpringApplicationRunListener environmentPrepared:org.springframework.boot.DefaultBootstrapContext@2a898881 SpringApplicationRunListener contextPrepared:org.springframework.context.annotation.AnnotationConfigApplicationContext@585811a4 SpringApplicationRunListener contextLoaded:org.springframework.context.annotation.AnnotationConfigApplicationContext@585811a4 SpringApplicationRunListener started:org.springframework.context.annotation.AnnotationConfigApplicationContext@585811a4 SpringApplicationRunListener running:org.springframework.context.annotation.AnnotationConfigApplicationContext@585811a4 ```
3.2 Custom Event Listener
In addition to using built-in listeners, you can also define and handle your own custom events.
To create and use custom events, follow these three steps:
- Define an Event Class:By extending the
ApplicationEvent
class. - Publish Events Where Needed:Use the
ApplicationEventPublisher.publishEvent(...)
method to trigger your event. - Define a Listener for Your Event:Implement the
ApplicationListener<YourEventClass>
interface in your listener class.
For example:
(1) Defining the Event Class:
```java public class CustomEvent extends ApplicationEvent { public String anyArg; public CustomEvent(Object source, String anyArg) { super(source); this.anyArg = anyArg; } } ```
(2) Creating a Listener:
```java @Component public class CustomEventListener implements ApplicationListener<CustomEvent> { @Override public void onApplicationEvent(CustomEvent event) { System.out.println("CustomEvent:" + event.anyArg); } } ```
(3) Publishing the Event: For this example, we’ll trigger the event through a Controller endpoint:
```java @RestController @RequestMapping("test") public class TestController { @Autowired private ApplicationEventPublisher eventPublisher; @GetMapping("/eventTest") public void eventTest() { eventPublisher.publishEvent(new CustomEvent(this, "myEvent")); } } ```
When the eventTest
endpoint is called, the listener’s method will be triggered, and the console will output:
``` CustomEvent:myEvent ```
4. Aspect-Oriented Programming (AOP) in Spring
4.1 Introduction to AOP
In object-oriented programming, we often deal with various business modules (e.g., creating orders, querying orders, dispatching tasks). These modules frequently require shared functionality, such as logging or permission checks. If we manually add this logic before and after every method, it introduces a high degree of coupling between business logic and auxiliary functionality. This not only makes the code less maintainable but also complicates future enhancements.
Aspect-Oriented Programming (AOP) addresses this challenge by separating cross-cutting concerns (e.g., logging, security) from the core business logic. With AOP, these concerns are injected into specific points of an application dynamically, rather than being scattered throughout the code. This approach keeps the core logic clean and improves maintainability and reusability.
At its core, AOP is an implementation of the Proxy Design Pattern. By using a proxy class, AOP intercepts method calls and injects additional logic before or after the core functionality.
Note: In the proxy pattern, an actual proxy class is generated. For instance, if there’s a
XxxxService
.class class in your application, enabling AOP will generate a proxy class likeXxxxService$Proxy.class
. When you call a method, you’re actually invoking it through this proxy class.
4.2 Static Proxy vs. Dynamic Proxy
In Java, implementing AOP (or the proxy pattern) typically involves two approaches: static proxy and dynamic proxy.
- Static Proxy:The proxy class and behavior are defined at compile-time. These classes can be handwritten or generated by tools/frameworks like
AspectJ
during the build process.- Advantages:High performance: Proxy classes are precompiled, so the JVM can directly load and execute them.
- Disadvantages:Inflexibility. Once compiled, the proxy logic and interception points are fixed and cannot be adjusted at runtime.
- Dynamic Proxy (Used by Spring AOP):A proxy class is generated at runtime using reflection and bytecode manipulation libraries such as CGLIB. The bytecode for the proxy class is created dynamically, enabling more flexible behavior.
- Advantages:Flexibility. Proxies and interception logic can be created and modified dynamically at runtime.
- Disadvantages:Lower performance(though not significant). Since the proxy classes are generated dynamically, this approach incurs additional overhead compared to static proxies. However, Spring mitigates this by pre-generating proxies during startup, reducing runtime overhead. This pre-generation is one reason why Spring applications can have slower startup times.
4.3 Implementing AOP in Spring
Using AOP in Spring is straightforward and involves three key steps:
- Define an Aspect Class::Create a class to represent the aspect. This class will contain the cross-cutting logic (e.g., logging). Annotate the class with
@Component
and@Aspect
. - Define a Pointcut: Specify the methods to which the cross-cutting logic should apply. Use the
@Pointcut
annotation to declare these interception points. - Define Advice:Implement the cross-cutting behavior. Use annotations such as
@Before
,@After
, or@Around
to mark methods as advice. These annotations determine when the logic should run (e.g., before or after the target method executes).
For example:
```java import org.aspectj.lang.JoinPoint; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; @Aspect // Marks this class as an Aspect, enabling Spring to recognize it as containing AOP logic. @Component // Tells Spring to manage this class as a Spring bean. public class LogAspect { // Defining a Pointcut: This specifies which methods will trigger the Aspect. // The syntax for defining Pointcuts is flexible and can be customized. See the official documentation: // https://docs.spring.io/spring-framework/reference/core/aop/ataspectj/pointcuts.html // Alternatively, you can skip defining a separate Pointcut method and directly embed expressions in annotations like @Before or @After. @Pointcut("execution(* com.*.MyService.*(..))") public void logPointcut() { } // Before Advice: Executes before the target method is called. @Before("logPointcut()") // Associates this advice with the logPointcut() Pointcut. public void beforeAdviceLog(JoinPoint joinPoint) { System.out.println("beforeAdviceLog"); } // After Advice: Executes after the target method completes. @After("logPointcut()") public void afterAdviceLog(JoinPoint joinPoint) { System.out.println("afterAdviceLog"); } // Around Advice: Allows custom logic before and after the target method is executed. @Around("logPointcut()") public Object aroundAdviceLog(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("Around beforeAdviceLog"); Object result = null; try { result = joinPoint.proceed(); // Invokes the target method and stores its return value. } catch (Throwable throwable) { // Handles exceptions thrown by the target method. // Typically, you might log the error and rethrow it for further handling. System.out.println("Around Exception"); throw throwable; } System.out.println("Around afterAdviceLog"); return result; // Returns the target method's return value. } } ```
Business Class is as follows:
```java @Service public class MyService { public void doSomething() { System.out.println("do something..."); } } ```
The output is as follows when the doSomething
is invoked:
``` Around beforeAdviceLog beforeAdviceLog do something... afterAdviceLog Around afterAdviceLog ```
4.4 Declaring Pointcuts
Pointcuts in Spring AOP can be declared using various types of expressions, designed to cover a wide range of use cases. These are the main types of pointcut expressions (refer to the official documentation):
- execution: This type matches methods based on their signatures. The expression follows the format:
execution(modifiers-pattern? return-type-pattern declaring-type-pattern? method-name-pattern(param-pattern) throws-pattern?)
- Example 1:
execution(public * com.example.service.*.*(..))
. Matches all public methods in thecom.example.service
package. - Example 2:
execution(* com.example.service.UserService.*(..))
. Matches all methods in theUserService
class. - Example 3:
execution(* com.example.service.*.*(java.lang.String, int))
. Matches methods in thecom.example.service
package that have parameters of typeString
andint
. - Example 4:
execution(* com.example.service.*.*() throws java.io.IOException)
. Matches methods in thecom.example.service
package that throw anIOException
. - Example 5:
execution(public static * com.example.service.*.*(..))
. Matches all public static methods in thecom.example.service
package.
- Example 1:
- within: This type matches based on the class to which a method belongs. The format is:
within(type-pattern)
. Note: Compared to execution, within provides broader matching. For more specific matching, prefer execution. - annotation:Matches methods annotated with a specific annotation. The format is:
@annotation(annotation-type)
。- Example 1:
@annotation(org.springframework.transaction.annotation.Transactional)
. Matches methods annotated with@Transactional
.
- Example 1:
- bean: Matches all methods within a specific Spring Bean based on its name.
- Example:
bean(accountService*)
. Matches all methods in beans whose names start withaccountService
. For example, if there is a bean namedAccountServiceImpl
, all its methods will match.
- Example:
Futhermore, Pointcuts can also be combined using &&
(AND), ||
(OR), and !
(NOT).
Examples:
```java @Pointcut("execution(* com.example.service.*.*(..)) && within(com.example.controller.*)") @Pointcut("execution(* com.example.service.*.*(..)) || execution(* com.example.dao.*.*(..))") @Pointcut("execution(* com.example.service.*.*(..)) && !execution(* com.example.service.internal.*.*(..))") ```