1. What is a framework
The representation of a framework in a project is a series of JARS, such as Thymeleaf.
Each framework addresses a specific problem, be it a development efficiency problem, or an operational efficiency problem, or a code management maintenance problem, and so on.
Using a frame in a project is like getting a “rough house”, and after using a frame, the developer only needs to worry about the “decoration” afterwards.
Most frameworks have a specific way to use, in use, must follow the framework of the use of rules!
Each framework can be the product of years of work by several developers or even development teams. For starters, try not to get too bogged down in understanding the underlying implementation principles of the framework!
Simply put: Using frameworks makes programming much easier! When learning frameworks, the proper way to use the main learning frameworks!
2. Dependencies
Suppose you need to develop a user registration feature in your project! Possible in the project:
public class UserRegServlet {
private UserDao userDao = new UserDao();
public void doPost(a) {
userDao.reg(); // Call the userDao object to store user data}}Copy the code
public class UserDao {
public void reg(a) {
// Store user data to a database using JDBC technology}}Copy the code
In the above code, the UserRegServlet relies on the UserDao!
3. The coupling
If a class relies too much on another class, it is often called “highly coupled”, which is not good for code management and maintenance. Simply put, if UserRegServlet relies on UserDao, one day the UserDao will no longer be able to meet the requirements of the project (perhaps because of a Bug in the code, Or the technology used is relatively backward, etc.), if the UserDao needs to be replaced, the difficult replacement will affect the management and maintenance of the project, the solution to solve this problem is called “decoupling”, making the dependency is not so clear, or even not clear!
To decouple the UserRegServlet from the UserDao, create an interface:
public interface IUserDao {
void reg(a);
}
Copy the code
Then, make the UserDao implement the above interface:
public class UserDao implements IUserDao {
public void reg(a) {
Reg () does exactly what reg() is supposed to do}}Copy the code
After the above adjustments, if the UserDao needs to be used in the UserRegServlet, the previous code would look like this:
private UserDao userDao = new UserDao();
Copy the code
Now you can change it to:
private IUserDao userDao = new UserDao();
Copy the code
The above code is equivalent to:
private List<String> strings = new ArrayList<>();
Copy the code
With this change, no matter how many Servlet components in the same project need to use the UserDao, the above syntax style can be used. If the UserDao needs to be replaced later, only the “assignment” code needs to be replaced. The declaration part does not need to be replaced! For example, to replace the UserDao with UserMybatisDao, the original code is:
private IUserDao userDao = new UserDao();
Copy the code
The new code could be:
public class UserMybatisDao implements IUserDao {
public void reg(a) {
// Use a better way to do what reg() should do}}Copy the code
In subsequent use, it can be:
private IUserDao userDao = new UserMybatisDao();
Copy the code
In other words, when UserDao is changed to UserMybatisDao, in each Servlet, only the content to the right of the equals sign needs to be adjusted, and the left part of the equals sign no longer needs to be modified!
Of course, the right side of the above code can be further treated using factory Design patterns:
public class UserDaoFactory {
// Return an object of interface type
public static IUserDao newInstance(a) {
return new UserDao(); // You can also return the UserMybatisDao object}}Copy the code
When you have a factory, the previous code can be further adjusted to:
private IUserDao userDao = UserDaoFactory.newInstance();
Copy the code
As you can see, none of the implementation class names appear in the above code anymore. Any Servlet component that needs to access the database can be declared as the above code. Later, if the implementation class needs to be replaced, only the return value of the factory method can be replaced.
In the actual project development, the dependence of the components in the project is more complex, and create the corresponding interface for each component factory is very troublesome, and the Spring framework is very good solve the problem, can simply understand the Spring as a “universal factory”, when using the Spring framework, don’t have to do the self-developed factory!
4. Introduction to the Spring Framework
What the Spring framework does: It solves the problem of creating and managing objects.
5. Create objects through Spring
Create a Maven Project. During the creation process, select Create a simple Project, set Group Id to cn.tedu, Artifact Id to Spring01, and leave other items as default.
When using the Spring framework, you must add a spring-context dependency to your project’s POM.xml:
<! -- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5. RELEASE</version>
</dependency>
Copy the code
First, in the project, create the cn.tedu.spring package and create the BeanFactory class under this package:
package cn.tedu.spring;
public class BeanFactory {}Copy the code
Currently, it doesn’t matter which package your code is in, get into the habit that every class should be in some package, and don’t let any class not be in any package!
The name of the above class is not important, it is custom!
If you want Spring to create and manage objects of a class, you must add a method to the above class:
- You should use
public
Permissions; - The return value type is the object type of the class that Spring needs to create and manage;
- Method names can be customized;
- The parameter list is temporarily empty;
- In the method body, write your own code to create a return value object.
Assuming Spring is needed to create an object of type Date, add a method to the class:
public Date aaa(a) {
// code
}
Copy the code
The Spring framework requires that methods that create objects must be annotated with @Bean annotations, and that such methods must be in the configuration class! Any class with the @Configuration annotation can be used as a Configuration class!
package cn.tedu.spring;
@Configuration
public class BeanFactory {
@Bean
public Date aaa(a) {
return newDate(); }}Copy the code
Once you’re done, you should use a runnable class or unit tests to see if you can get objects from the Spring container. Create a runnable class:
package cn.tedu.spring;
public class SpringTests {
public static void main(String[] args) {
// 1. Load the configuration class to get the Spring container
AnnotationConfigApplicationContext ac
= new AnnotationConfigApplicationContext(BeanFactory.class);
// 2. Get the required objects from the Spring container
Date date = (Date) ac.getBean("aaa"); The argument to the getBean() method is the name of the method that created the object
// 3. Test the acquired object
System.out.println(date);
/ / 4. Shut downac.close(); }}Copy the code
6. About @bean annotations
When a method declaration is preceded by the @bean annotation, it means that the method needs to be called by the Spring framework, and that the Spring framework manages the object returned by the method! By default, the name of this method is the argument to call the getBean() method when you get the object later!
Due to add @ Bean annotation method is to be invoked by the Spring framework, don’t need to write code to call this method, so the Spring’s advice is to “use reasonable property name as a method name, do not need to use a verb or a verb to prefix the name of the method”, in short, if the method is to get the Date type of the object, The name of the method should be date, not getDate(), and the subsequent calls to getBean() will take the name date!
Of course, if you don’t follow Spring’s advice, you can also configure the annotation parameter in the @bean annotation to specify the Bean name, for example:
@Bean("date")
public Date getDate(a) {
return new Date();
}
Copy the code
The object is then fetched according to the annotation parameter:
Date date = (Date) ac.getBean("date");
Copy the code
Its relationship is shown as follows:
In fact, in the development of the project, you really don’t need to worry about these problems, that is, for example, a method to get a Date object, whether the name is Date or getDate is correct! After all, this method is ultimately called by the Spring framework; developers don’t call it themselves!
7. Scope of Spring managed objects
Objects managed by Spring are, by default, singletons! So, the scope is very long!
In the case of Spring-managed objects, talking about the scope of an object is essentially talking about whether it’s a singleton!
Adding the @scope annotation and setting the annotation parameter to prototype before creating the object’s method makes the object non-singleton:
@Scope("prototype")
@Bean
public User user(a) {
return new User();
}
Copy the code
Objects managed by Spring, if singleton, are hunky-dory by default! Before creating the object’s method, add the @lazy annotation to make it Lazy:
@Bean
@Lazy
public User user(a) {
return new User();
}
Copy the code
In general, the scope of an object is rarely adjusted when developing a project!
8. Summary of the day:
- The main functions of Spring are to create and manage objects.
- If a method is used to create objects for the Spring framework, that method must be added
@Bean
Annotations; - All added
@Bean
Annotated methods should be added to the class@Configuration
Notes, where added@Configuration
The annotation class is calledThe configuration class; - By default, objects managed by Spring are singletons, using
@Scope
Annotations make spring-managed objects “non-singleton”; - By default, singleton objects managed by Spring are “hungry”, used
@Lazy
You can change them to “slacker”.
Appendix 1: Singleton patterns for design patterns
Singleton: There must be at most one object of a class at a time! You may try to get the object many times, but you will get the same object!
Suppose you have a King class in your project:
public class King {}Copy the code
Obviously, it is not singleton at present, because it can:
King k1 = new King();
King k2 = new King();
King k3 = new King();
Copy the code
This code creates three objects of type King! If you want to implement a singleton, you must first restrict access to the constructor, for example:
public class King {
private King(a) {}}Copy the code
Each class can have several constructors, and if a class does not explicitly declare any constructors, the compiler automatically adds a public, no-argument constructor! If any constructors are already declared in a class, the compiler does not automatically add constructors!
Since the constructor is declared private, the original King k1 = new King(); This kind of code cannot be used to create objects!
Restrict access to constructors. The purpose is to “disallow arbitrary object creation”, not “disallow object creation”. Inside the King class, objects can still be created, and methods can be added to return internally created objects:
public class King {
private King king = new King();
private King(a) {}public King getInstance(a) {
returnking; }}Copy the code
So, when you need an object of type King, you can get it using the getInstance() method!
However, the above code is not feasible! Because if you want to call getInstance(), you must first get the King object, and the only way to get the King object is to call getInstance()! To solve this problem, the static modifier must be added before the declaration of the getInstance() method, and finally, through the class name. The syntactic format of the method name () to call the method! The global king attribute must also be static, because “static members cannot access other members that are not static” :
public class King {
private static King king = new King();
private King(a) {}public static King getInstance(a) {
returnking; }}Copy the code
At this point, the basic singleton pattern code design is complete!
The above code is the hungrier singleton pattern, and there is also the lazy singleton pattern!
The code for the basic lazy singleton is:
public class King {
private static King king = null;
private King(a) {}public static King getInstance(a) {
if (king == null) {
king = new King();
}
returnking; }}Copy the code
Note: the above code is multithreaded unsafe!
In the development world, whenever data is produced or changed differently than the developer expected, it is called an “insecure” or “data security problem.”
To ensure thread-safety, the code snippet that created the object above should be “locked”, for example:
public class King {
private static King king = null;
private King(a) {}public static King getInstance(a) {
synchronized ("hello") {
if (king == null) {
king = newKing(); }}returnking; }}Copy the code
Of course, whenever any thread executes the above code, it must “lock” the code snippet before it can start executing. This is not necessary, and the performance cost of “locking” is wasteful, so it can be further adjusted to:
public class King {
private static King king = null;
private King(a) {}public static King getInstance(a) {
if (king == null) { // Determine if it is necessary to lock the following code
synchronized ("java") {
if (king == null) { // Determine if it is necessary to create an object
king = newKing(); }}}returnking; }}Copy the code
Now the lazy singleton pattern is complete!