A brief discussion of the core ideas of Spring

I still remember that when I first learned Spring, I still had to write XML files one after another. I didn't know why at the time. I followed the steps on the Internet to configure them one by one. If I mismatched one, I was confused for a long time and looked at the error. I just made random changes until it could run in the end. Secretly sighing tmd this thing is really complicated.

Later, when I used SpringBoot, it seemed that a lot of XML configuration was missing, and I was secretly happy. At first, it ran normally according to the default configuration. Later, when I needed to make changes, I didn't know where to start.

It can be used muddle-headedly most of the time, but if you encounter strange problems, you have to ask Lao Li for help.

Later I discovered that there is Spring Cloud, and the era of microservices is coming. I think I can no longer use Spring Family Bucket like this.

I dived into various SpringCloud detailed source codes at once, hoping to understand the true meaning of the framework. In the end, I came back with no success and was dejected. I once again lamented that tmd is really complicated.

During this time, I have realized that I am not familiar with the Spring basic framework, which leads to me not understanding many encapsulation points.

After all, SpringCloud is based on SpringBoot, and SpringBoot is based on Spring.

So I went back to learn Spring again. Instead of immersing myself in various details, I changed my strategy. I first overview Spring from a high-dimensional perspective, understand the core principles, and then conquer various branches.

So I, I became stronger.

In fact, it is the same when learning anything. You must first get an overview and then go deep into it, and then summarize it after looking back.

In this article, I intend to use my own understanding to explain the core (idea) of Spring. Due to my personal expression ability, there may be errors or verbosity. Please bear with me. If there are any errors, please point them out.

Put aside IOC and DI and think about why Spring is needed

When we first learn Java, we naturally write code like this:

public class ServiceA { 
  private ServiceB serviceB = new ServiceB();
}
复制代码

We encapsulate some logic into ServiceB , and when ServiceAit needs to use these logic, it will be ServiceAinside .new ServiceB

If ServiceB the encapsulated logic is very general, there will be ServiceCother ServiceFthings that need to rely on it, which means that new ones are needed everywhere in the code ServiceB . In this way, if its construction method changes, you have to use it in all places. Go to its place and make code modifications.

For example, ServiceB if you need to create an instance ServiceC , the code should be changed to this:

public class ServiceA { 
  private ServiceB serviceB = new ServiceB(new ServiceC());
}
复制代码

There is indeed this problem.

But in fact, if we encapsulate common servicelogic, there is no need to create new instances every time. In other words, a single instance is enough. Our system only needs newone ServiceB for each object to solve this problem.

public class ServiceA { 
  private ServiceB serviceB = ServiceB.getInstance();
}

public class ServiceB {
    private static ServiceB instance = new ServiceB(new ServiceC());
    private ServiceB(){}
    public static ServiceB getInstance(){
        return instance;
    }
}
复制代码

It looks like the problem has been solved, but it is not.

When the project is relatively small, such as a large university assignment, the above operation is actually not a big problem, but it becomes complicated when it comes to enterprise-level applications.

ServiceB1Because there is a lot of logic involved, there are many encapsulated service classes, and the dependencies between them are also complicated. There may be , ServiceB2... in the code ServiceB100, and there may be dependencies between each other.

Putting dependencies aside, just take ServiceBsimple singleton logic code. Repeated logic may need to be written in hundreds or thousands of copies .

And it is not easy to expand . In the past, the operation of ServiceB may not require transactions, but later transactions will be required. Therefore, ServiceBthe code needs to be modified to embed transaction-related logic.

Not long ServiceCafter, transactions were also required, and the exact same code about transactions had to be repeated on ServiceC, as well as D, E, F...

The requirements for several Servicetransactions are different, and there is also the problem of nested transactions. In short, it is a bit troublesome.

I have been busy for a while to meet transaction requirements and went online. I thought I was finally free from the nightmare of repeated code and could take a good rest.

Then came another requirement. Because we often need to troubleshoot online problems, we need to log the interface input parameters to facilitate troubleshooting, and we have to make drastic changes all at once.

It is normal to make changes when necessary, but each change requires a lot of repetitive work, which is tiring, has no technical content, and is easy to miss . This is not elegant enough.

So some people started to think of ways to get out of this coupling quagmire.

Elevation and stripping

Most of human inventions are due to laziness. People hate repetitive work, and computers love and are best suited to do repetitive work .

Since there will be a lot of repetitive work in previous development, why not create a "thing" to help us do such repetitive things ?

Just like in the past, people assembled and manufactured products step by step by hand, and the same steps may be repeated tens of thousands of times every day. Later, people developed fully automatic machines to help us manufacture products, freeing people's hands and improving production efficiency.

After improving this idea, the coding logic changed from us programmers thinking and writing that ServiceA depends on a specific ServiceB, and typing out the code letter by letter on how ServiceB is instantiated, to that we only care about ServiceA depending on ServiceB , but we don't care how ServiceB is generated, that "thing" helps us generate it and associate ServiceA and ServiceB.

public class ServiceA { 
  @注入
  private ServiceB serviceB;
}
复制代码

It may sound a bit unreal, but it’s not.

Let’s talk about machines again. We create this machine. If we want to produce product A, we only need to draw drawing A and stuff drawing A into this machine. The machine will recognize drawing A and produce what we want according to the design of our drawing A. Product A.

Spring is this machine , and the drawings rely on the object codes managed by Spring and those XML files (or annotated @Configurationclasses).

This is when the logic changes. Programmers know ServiceAwhich one they depend on ServiceB, but we don't need to explicitly write the complete logic on how to create ServiceB in the code. We only need to write the configuration file, and Spring will help us with the specific creation and association.

Continuing to take the example of the machine, we are given the drawings (configuration), and the machine helps us make the product. We don’t need to worry about how to make it, but we know it, because our drawings indicate ServiceAwhat is needed for manufacturing ServiceB, and that What kind of logic ServiceBis needed ?ServiceC

I am looking for a drawing example, the configuration of the database in Spring:

You can see that our drawings are written very clearly. When creating, mybatisyou MapperScannerConfigurerneed to tell it the values ​​​​of two attributes. For example, the first one is sqlSessionFactoryBeanName, and the value is sqlSessionFactory.

And itsqlSessionFactory depends on it dataSource, and dataSourceit needs to be configured driverClassName, urletc.

Therefore, we actually know very well what is needed to create a product (Bean), but the creation process is handled by Spring. We only need to tell it clearly.

Therefore, it does not mean that with Spring we no longer care about ServiceAthe specific dependencies ServiceBand ServiceBhow they are successfully created, but that the process of assembling these objects is done for us by Spring.

We still need to know clearly how the object is created, because we need to draw the correct drawing to tell Spring.

So Spring is actually a machine that automatically creates associated objects for us to use based on the drawings we give it. We don't need to explicitly write the complete creation code in the code .

These object instances created by Spring are called Beans.

If we want to use these beans, we can get them from Spring. Spring puts these created singleton beans in a Map, and we can get these beans by name or type.

This is IOC .

Precisely because these beans need to be created by the Spring machine, instead of lazily creating them in every corner of the code, we can easily do many things based on this unified interface.

For example, when our ServiceBis marked with @Transactionalan annotation, Spring will understand that this annotation ServiceBrequires a transaction, so it can start, commit, rollback and other operations of the woven transaction.

Everything marked with @Transactionalan annotation will automatically add transaction logic, which reduces too much repetitive code for us. As long as we add @Transactionalannotations to the methods or classes that require transactions, Spring will help us supplement the transaction function. Repeated operations are done by Spring is complete.

For another example, we need to record the request input parameters on all controllers. This is also very simple. We only need to write a configuration to tell Spring that the input parameters of each method of the class under the xxx path (controller package path) need to be recorded in the log. , and also write the log printing logic code.

Spring got this command after parsing this configuration, so when creating the subsequent Bean, we will see if the package it is in conforms to the above configuration. If it does, we will add log printing logic and weave it together with the original logic. .

In this way, the repeated log printing action operations are abstracted into a configuration. After the Spring machine recognizes the configuration, it executes our commands to complete these repeated actions.

This is called AOP .

At this point, I believe you have a certain understanding of the origin and core concepts of Spring. There are many things that can be done based on the above features.

Because of the unified closing processing of Spring, we can flexibly provide many extension points at different times, such as when configuration files are parsed, before and after Bean initialization, before and after Bean instantiation, etc.

Based on these extension points, many functions can be implemented, such as selective loading of beans, replacement of placeholders, and generation of proxy classes (transactions, etc.).

For example SpringBoot Redis, when selecting a client, two client configurations of lettuceand will be imported by default.jedis

Based on the configuration order, lettuce will be imported first, and then jedis will be imported.

If the scan finds lettuce, then use lettuce's RedisConnectionFactory. When loading jedis later, it will be based on @ConditionalOnMissingBean(RedisConnectionFactory.class)to ensure that jedis will not be injected, otherwise it will be injected.

ps:@ConditionalOnMissingBean(xx.class) If there is currently no xx.class, the bean modified by this annotation can be generated.

The above feature is implemented based on the extension points provided by Spring.

It is very flexible for us to replace the required redis client without changing any code used. We only need to change the dependency. For example, to change from the default lettuce to jedis, we only need to change the maven configuration, remove the lettuce dependency, and introduce jedis:

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-data-redis</artifactId>
    <exclusions>
        <exclusion>
            <groupId>io.lettuce</groupId>
            <artifactId>lettuce-core</artifactId>
        </exclusion>
    </exclusions>
</dependency>
<dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
</dependency>
复制代码

What I really want to say is that the extensions and encapsulation provided by Spring Family Bucket can flexibly meet our many needs, and these flexibilities are based on Spring's core IOC and AOP .

at last

Finally, I use a paragraph to briefly describe the principle of Spring:

Spring parses the contents according to the configuration class and XML configuration file we provide, and obtains the information of the beans it needs to manage and the relationships between them. And Spring exposes many extension points for us to customize, such as, , we only need to BeanFactoryPostProcessorimplement BeanPostProcessorthis The interface can perform some customized operations.

After Spring obtains the Bean information, it will create a Bean instance based on reflection and assemble the dependencies between the Beans. It will intersperse native or our-defined dependencies to transform the Bean, replace PostProcessorsome attributes or proxy the original Bean logic.

Finally, after all the beans with configuration requirements are created, the singleton beans are stored in the map, and the BeanFactory is provided for us to obtain and use the beans.

This allows us to no longer need to pay attention to how the Bean is created during the coding process, and also saves a lot of repetitive coding actions. These are all done for us by the machine we created - Spring.

That's probably all I have to say. I have read it several times and I don't know if I have clearly explained what I want to express. In fact, I originally talked about the core from the source code level, but I'm afraid it will be harder to explain clearly.

Finally, I have written the interview answers about Spring's IOC and DI concepts before. You can take a look at the URL: https://yessimida.gitee.io/interview-of-legends/#/./docs/c-1Spring%E7%B2%BE%E9%80%89%E9%9D%A2%E8%AF%95%E9%A2%98%E8%A7%A3.

Guess you like

Origin blog.csdn.net/2301_76607156/article/details/130525822
Recommended