This article is excerpted from the author's open source Java Study & Interview Guide (Github harvested 146k star):JavaGuide 。
This article explains IoC & AOP from the following questions
- What is IoC?
- What problem does IoC solve?
- Difference between IoC and DI?
- What is AOP?
- What problem does AOP solve?
- What are the application scenarios for AOP?
- AOP Why is it called faceted programming?
- What are the AOP implementations?
First of all, IoC & AOP is not Spring proposed, they actually existed before Spring, but at that time more inclined to the theory, Spring in the technical level of these two ideas for a good implementation.
IoC (Inversion of control )
What is IoC?
IoC (Inversion of Control) i.e. Inversion of Control / Inversion of Control. It is an idea not a technical implementation. Description: Java development domain object creation and management issues.
For example, an existing class A depends on class B
- Traditional development approach : Often an object of B is manually created in class A with the new keyword.
- A development approach using IoC thinking Instead of creating objects with the new keyword, we use the IoC container (Spring Framework) to help us instantiate objects. We need which object, directly from the IoC container to fetch it.
From the comparison of the above two development styles: we "lose a power" (the power to create and manage objects), and thus gain one (not having to think about object creation, management, and a host of other things)
Why do you call it a control reversal?
- containment : refers to the power to create (instantiate, manage) objects
- invert (upside-down, inside-out, back-to-front, white to black etc) : control to the external environment (IoC container)
What problem does IoC solve?
The idea of IoC is that the two parties do not depend on each other, and the third party container manages the relevant resources. What are the benefits of this?
- There is less coupling, or dependency, between objects;
- Resources become easier to manage; for example, you can easily implement a single instance if you use the Spring container to provide it.
For example, there is an existing operation for Users, which is developed using the two-tier structure of Service and Dao.
In the absence of IoC thinking, if the Service tier wants to use the specific implementation of the Dao tier, it needs to use the new keyword in theUserServiceImpl
Manually new out of theIUserDao
The concrete implementation class of theUserDaoImpl
(you can't directly new interface classes).
It's perfect, and this approach is possible, but let's imagine the following scenario:
A new requirement was suddenly received during the development process for theIUserDao
interface develops another concrete implementation class. Because the Server layer relies on theIUserDao
implementation, so we need to modify theUserServiceImpl
The new object in the If only one class references theIUserDao
implementation, it might feel okay and not be a lot of work to modify, but if there are many, many references to theIUserDao
If the specific implementation of theIUserDao
implementation, that would be a huge headache to modify.
With the IoC idea, we leave the control (creation, management) of the object to the IoC container, and we "ask" the IoC container for it when we use it.
Is there a difference between IoC and DI?
IoC (Inverse of Control) is a design idea or a pattern. The design idea is thatGiving control to a third party such as an IoC container that would otherwise create objects manually in the program. For our common Spring framework, the IoC container is actually a Map (key, value), Map is stored in a variety of objects. However, IoC is also used in other languages and is not unique to Spring.
The most common and logical implementation of IoC is called Dependency Injection (DI).
Martin Fowler, Sr. mentions changing the name of IoC to DI in an article that follows the original address:/articles/ 。
What the old horse probably meant was that IoC is so common and unintuitive that many people get confused by it, so it's better to use DI to precisely name the pattern.
AOP(Aspect oriented programming)
Here will not involve too much specialized terminology, the core purpose is to make the idea of AOP clear.
What is AOP?
AOP (Aspect Oriented Programming) that is, cutter-oriented programming, AOP is a continuation of OOP (Object Oriented Programming), the two complement each other and are not opposed.
The purpose of AOP is to separate cross-cutting concerns (such as logging, transaction management, privilege control, interface flow restriction, interface power, etc.) from the core business logic, and realize code reuse and decoupling through dynamic agents, bytecode manipulation, and other techniques, to improve code maintainability and scalability.The purpose of OOP is to encapsulate the business logic according to the object's attributes and behaviors, and realize modularization and hierarchization of code (which also enables code reuse) through concepts such as classes, objects, inheritance, polymorphism, and so on, Inheritance, polymorphism and other concepts, to achieve modularity and hierarchy of the code (can also achieve code reuse), to improve the readability and maintainability of the code.
AOP Why is it called cutter-oriented programming?
AOP is called cutter-oriented programming because its core idea is to separate cross-cutting concerns from the core business logic to form aAspect。
Here's a passing summary of key AOP terms (it's okay if you don't understand them, read on):
- Cross-cutting concerns (cross-cutting concerns) : Public behavior in multiple classes or objects (e.g., logging, transaction management, privilege control, interface flow restriction, interface powers, etc.).
- Aspect: A class that encapsulates a cross-cutting concern, a facet is a class. A facet can define multiple notifications that are used to implement specific functionality.
- JoinPoint: A connection point is a method call or a specific moment in method execution (e.g., method invocation, exception throw, etc.).
- Advice: A notification is an action to be performed by a facet at a certain connection point. There are five types of notifications, namely Before, After, AfterReturning, AfterThrowing and Around. The first four types of notifications are executed before and after the target method, while the surround notification can control the execution process of the target method.
-
Pointcut: A cutpoint is an expression that is used to match which connections need to be augmented by a facet. Cutpoints can be defined by annotations, regular expressions, logical operations, and so on. For example
execution(* ..*(..))
matchA class or interface under a package and its subpackages.
- Weaving: Weaving is the process of connecting a facet to a target object, i.e., applying a notification to a connection point that matches a cutpoint. There are two common weaving timing, respectively, compile-time weaving (Compile-Time Weaving, such as: AspectJ) and run-time weaving (Runtime Weaving, such as: AspectJ, Spring AOP).
AOP What are the common types of notifications?
- Before(pre-notification): triggered before the target object's method call
- After (post notification): triggered after a method call on the target object
- AfterReturning(return notification): the target object's method call completes, triggered after the result value is returned.
- AfterThrowing(Exception Notification): triggered when an exception is thrown/triggered during the target object's method operation.AfterReturning and AfterThrowing are mutually exclusive. AfterReturning and AfterThrowing are mutually exclusive. If the method call succeeds without exception, there will be a return value; if the method throws an exception, there will be no return value.
- Around (Wrap-around notification): Programmatically control method calls on the target object. Surround notification is one of the notification types with the largest scope of operation, because it can directly get the target object, and the method to be executed, so surround notification can arbitrarily in the target object before and after the method call to do something, or even do not call the target object's method
What problem does AOP solve?
OOP doesn't handle well some public behaviors (e.g., logging, transaction management, privilege control, interface flow restriction, interface power, etc.) that are spread across multiple classes or objects, which are often referred to asCross-cutting concerns (cross-cutting concerns) . If we repeatedly implement these behaviors in every class or object, it leads to redundant, complex, and hard-to-maintain code.
AOP can remove cross-cutting concerns (e.g., logging, transaction management, privilege control, interface flow restriction, interface power, etc.) from theCore business logic (core concerns) in the separation of concerns is achieved.
Take logging as an example, if we need to log certain methods in a uniform format, without using AOP technology, we need to write the logging logic code one by one, which is all repetitive logic.
public CommonResponse<Object> method1() {
// Business logic
xxService.method1(); // Omit the specific business logic.
// Omit the specific business logic
// Logging
ServletRequestAttributes attributes = (ServletRequestAttributes) ();
HttpServletRequest request = (); // Omit logging logic.
// Omit the logging logic, e.g., fetching various information, writing to the database, etc...
return ();
}
public CommonResponse<Object> method2() {
// Business logic
xxService.method2(); // Omit the specific business logic.
// Omit the specific business logic
// Logging
ServletRequestAttributes attributes = (ServletRequestAttributes) ();
HttpServletRequest request = (); // Omit logging logic.
// Omit the logging logic, e.g., fetching various information, writing to the database, etc...
return ();
}
// ...
Using AOP techniques, we can encapsulate the logging logic into a cutout, and then specify the methods in which the logging operations need to be performed, using entry points and notifications.
// Log annotations
@Target({,})
@Retention()
@Documented
public @interface Log {
/**
* Description
*/
String description() default "";
/**
* Method type INSERT DELETE UPDATE OTHER
*/
MethodType methodType() default ;
}
// Logging cutout
@Component
@Aspect
public class LogAspect {
// Entry point for all methods annotated with Log.
@Pointcut("@annotation()")
public void webLog() {
}
/**
* Wrap-around notifications
*/
@Around("webLog()")
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
// Omit the specific processing logic
}
// Omit the rest of the code
}
In that case, we can implement logging with one line of annotations:
@Log(description = "method1",methodType = )
public CommonResponse<Object> method1() {
// Business Logic
xxService.method1(); // Omit the specific business logic.
// Omit the specific business logic
method1(); // Omit the specific business logic.
}
What are the application scenarios for AOP?
- Logging: custom logging annotations , using AOP , a line of code to achieve logging .
- Performance statistics: Use AOP to count the execution time of the method before and after the execution of the target method to facilitate optimization and analysis.
- Management of services:
@Transactional
Annotations allow Spring to perform transaction management such as rolling back exceptions for us, eliminating the need for repetitive transaction management logic.@Transactional
Annotations are implemented based on AOP. - Permission control: AOP is used to determine whether the user has the required permissions before the execution of the target method, if so, the target method is executed, otherwise it is not executed. For example, SpringSecurity utilizes
@PreAuthorize
Annotate one line of code to customize permission checks. - Interface flow limiting: AOP is utilized to limit the flow of requests through specific flow limiting algorithms and implementations before the execution of the target method.
- Cache Management: Using AOP to read and update the cache before and after the execution of the target method.
- ……
What are the AOP implementations?
Common implementations of AOP include dynamic proxies, bytecode manipulation, and other methods.
Spring AOP is based on dynamic proxying. If the object to be proxied implements an interface, then Spring AOP will use theJDK Proxyto create a proxy object, but for objects that do not implement the interface, it is not possible to use the JDK Proxy to proxy them, then Spring AOP will use theCglib Generate a subclass of the object being proxied to act as a proxy, as shown below:
Of course you can also useAspectJ Spring AOP has integrated AspectJ, which should be considered the most complete AOP framework in the Java ecosystem.
Spring AOP is a runtime enhancement, while AspectJ is a compile-time enhancement. Spring AOP is based on Proxying (Proxying), while AspectJ is based on Bytecode Manipulation (Bytecode Manipulation).
Spring AOP has integrated AspectJ, which is the most complete AOP framework in the Java ecosystem; AspectJ is more powerful than Spring AOP, but Spring AOP is relatively simple.
If we have fewer facets, then there is little difference in performance between the two. However, when there are too many facets, it is better to choose AspectJ, which is much faster than Spring AOP.