Spring learning notes

SPRING learning notes

Common Spring modules

Spring IOC

The core container provides the basic functions of the spring framework. The main component of the core container is BeanFactory
It is the implementation of the factory pattern. BeanFactory uses the inversion of control IOC pattern to separate the configuration and dependency specifications of the application from the actual application code

Spring context

Spring context is a configuration file that provides context information to the spring framework. Spring context includes enterprise services
For example, JNDI EJB email internationalization (i18n) checksum scheduling function

Spring AOP

Through the configuration management feature, spring aop directly integrates aspect oriented programming into the spring framework, and can integrate some common tasks
For example, security, events and logs are managed in a centralized way, which improves the reusability and convenience of management

Spring DAO

Spring ORM inserts several ORM frameworks to provide ORM object relationship tools, including
jdo, ibaties sql map, all of which follow spring's common things and DAO exception hierarchy

SpringBean

spring 3 defines five scopes for beans, which are singleton, prototype, request, session and global session

Spring WEB module

Web context is built on the application context and provides context for web-based programs

Spring MVC framework

MVC is a fully functional implementation of building WEB applications. Through the policy interface, MVC becomes highly configurable
MVC accommodates a large number of view technologies, including JSP, Velocity, Tiles, iText

Spring/SpringBoot common annotations

Article directory

1. @SpringBootApplication

Here, take out the @SpringBootApplication note to explain, although we generally do not take the initiative to use it.

Brother Guide: this annotation is the cornerstone of the Spring Boot project. After the SpringBoot project is created, it will be added to the main class by default.

@SpringBootApplication
public class SpringSecurityJwtGuideApplication {
      public static void main(java.lang.String[] args) {
        SpringApplication.run(SpringSecurityJwtGuideApplication.class, args);
    }
}

We can regard @SpringBootApplication as a collection of @Configuration, @EnableAutoConfiguration and @ComponentScan annotations.

package org.springframework.boot.autoconfigure;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
		@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
		@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
   ......
}

package org.springframework.boot;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {

}

According to the SpringBoot official website, the functions of these three annotations are:

  • @EnableAutoConfiguration: enables the SpringBoot auto configuration mechanism
  • @ComponentScan: scan bean s annotated by @Component (@Service,@Controller). The annotation will scan all classes under the package where the class is located by default.
  • @Configuration: allows you to register additional bean s or import other configuration classes in the Spring context

2. Spring Bean related

2.1. @Autowired

Automatically import objects into classes. The injected classes should also be managed by the Spring container. For example, the Service class should be injected into the Controller class.

@Service
public class UserService {
  ......
}

@RestController
@RequestMapping("/users")
public class UserController {
   @Autowired
   private UserService userService;
   ......
}

2.2. @Component,@Repository,@Service, @Controller

We usually use the @Autowired annotation to let the Spring container help us assemble beans automatically. To identify the class as a class that can be used to annotate the bean automatically assembled by @Autowired, you can use the following annotation:

  • @Component: a general annotation that can label any class as a Spring component. If a Bean does not know which layer it belongs to, it can be annotated with the @component annotation.
  • @Repository: the corresponding persistence layer, namely Dao layer, is mainly used for database related operations.
  • @Service: corresponding to the service layer, which mainly involves some complex logic and requires the Dao layer.
  • @Controller: corresponds to the Spring MVC control layer. It is mainly used to accept user requests and call the Service layer to return data to the front-end page.

2.3. @RestController

@The RestController annotation is a collection of @Controller and @ResponseBody, which indicates that this is a Controller bean and directly fills the return value of the function into the HTTP response body. It is a REST style Controller.

Brother Guide: now the front and back ends are separated. To be honest, I haven't used @Controller for a long time. If your project is too old, treat it as if I didn't say it.

If you use @controller alone without @ResponseBody, it is generally used when you want to return a view. This is a traditional Spring MVC application, which corresponds to the situation that the front and back ends are not separated@ Controller +@ResponseBody returns JSON or XML data

For the comparison between @RestController and @Controller, please see this article: @RestController vs @Controller.

2.4. @Scope

Declare the scope of Spring Bean, using the following method:

@Bean
@Scope("singleton")
public Person personSingleton() {
    return new Person();
}

Four common scopes of spring beans:

  • singleton: a unique bean instance. All beans in Spring are singletons by default.
  • prototype: each request creates a new bean instance.
  • Request: each HTTP request will generate a new bean, which is only valid within the current HTTP request.
  • Session: each HTTP request will generate a new bean, which is only valid in the current HTTP session.

2.5. @Configuration

It is generally used to declare Configuration classes, which can be replaced by the @Component annotation. However, it is more semantic to declare Configuration classes with the @Configuration annotation.

@Configuration
public class AppConfig {
    @Bean
    public TransferService transferService() {
        return new TransferServiceImpl();
    }

}

3. handle common HTTP request types

Five common request types:

  • GET: requests to GET a specific resource from the server. For example: GET /users
  • POST: create a new resource on the server. For example: POST /users (create students)
  • PUT: update the resources on the server (the client provides the entire updated resources). For example: PUT /users/12 (student with update number 12)
  • DELETE: deletes a specific resource from the server. For example: DELETE /users/12
  • PATCH: updates the resources on the server (the client provides the changed attributes, which can be seen as partial updates). It is rarely used. There are no examples here.

3.1. GET request

@GetMapping("users") is equivalent to @RequestMapping(value="/users",method=RequestMethod.GET)

@GetMapping("/users")
public ResponseEntity<List<User>> getAllUsers() {
 return userRepository.findAll();
}

3.2. POST request

@PostMapping("users") is equivalent to @RequestMapping(value="/users",method=RequestMethod.POST)

The use of the @RequestBody annotation will be discussed in the following "front and back end value transfer".

@PostMapping("/users")
public ResponseEntity<User> createUser(@Valid @RequestBody UserCreateRequest userCreateRequest) {
 return userRespository.save(user);
}

3.3. PUT request

@PutMapping("/users/{userId}") is equivalent to @RequestMapping(value="/users/{userId}",method=RequestMethod.PUT)

@PutMapping("/users/{userId}")
public ResponseEntity<User> updateUser(@PathVariable(value = "userId") Long userId,
  @Valid @RequestBody UserUpdateRequest userUpdateRequest) {
  ......
}

3.4. DELETE request

@DeleteMapping("/users/{userId}") is equivalent to @RequestMapping(value="/users/{userId}",method=RequestMethod.DELETE)

@DeleteMapping("/users/{userId}")
public ResponseEntity deleteUser(@PathVariable(value = "userId") Long userId){
  ......
}

3.5. PATCH request

In general, in actual projects, we use the PATCH request to update the data after the PUT is not enough.

  @PatchMapping("/profile")
  public ResponseEntity updateStudent(@RequestBody StudentUpdateRequest studentUpdateRequest) {
        studentRepository.updateDetail(studentUpdateRequest);
        return ResponseEntity.ok().build();
    }

4. front and rear end value transmission

Mastering the correct posture of front and back end value transmission is the first step for you to start CRUD!

4.1. @PathVariable and @RequestParam

@PathVariable is used to obtain path parameters, and @RequestParam is used to obtain query parameters.

A simple example:

@GetMapping("/klasses/{klassId}/teachers")
public List<Teacher> getKlassRelatedTeachers(
         @PathVariable("klassId") Long klassId,
         @RequestParam(value = "type", required = false) String type ) {
...
}

If the url we requested is: /klasses/{123456}/teachers?type=web

The data obtained by our service is: klassId=123456,type=web.

4.2. @RequestBody

It is used to read the data in the body part of the Request (possibly POST,PUT,DELETE,GET requests) and the content type is in application/json format. After receiving the data, it will automatically bind the data to the Java object. The system will use HttpMessageConverter or customized HttpMessageConverter to convert JSON strings in the requested body into Java objects.

I use a simple example to demonstrate the basic use!

We have a registered interface:

@PostMapping("/sign-up")
public ResponseEntity signUp(@RequestBody @Valid UserRegisterRequest userRegisterRequest) {
  userService.save(userRegisterRequest);
  return ResponseEntity.ok().build();
}

UserRegisterRequest object:

@Data
@AllArgsConstructor
@NoArgsConstructor
public class UserRegisterRequest {
    @NotBlank
    private String userName;
    @NotBlank
    private String password;
    @NotBlank
    private String fullName;
}

We send a post request to this interface, and the body carries JSON data:

{"userName":"coder","fullName":"shuangkou","password":"123456"}

In this way, our backend can directly map the json format data to our UserRegisterRequest class.

[external link image transfer failed. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-lyfzlq75-1617893998921) (f:/typera/imgs/@requestbody.png)]

πŸ‘‰ It should be noted that a request method can only have one @RequestBody, but can have multiple @RequestParam and @PathVariable. If your method must use two @requestbodies to receive data, it is likely that there is a problem with your database design or system design!

5. read configuration information

Many times, we need to put some commonly used configuration information, such as Alibaba cloud oss, SMS sending, wechat authentication, and so on, into the configuration file.

Let's take a look at how Spring provides us with ways to read the configuration information from the configuration file.

Our data source application The contents of YML are as follows:

wuhan2020: 2020 At the beginning of the year, there was a serious outbreak of novel coronavirus in Wuhan. However, I believe everything will pass! Come on, Wuhan! Go China!

my-profile:
  name: Guide brother
  email: koushuangbwcx@163.com

library:
  location: Hubei Wuhan refueling China refueling
  books:
    - name: Genius Basic Law
      description: On the day when his father diagnosed Alzheimer's disease, Lin Chaoxi, 22, learned that Peizhi, the campus male God whom he had secretly loved for many years, was about to go abroad for further study - the school that the other party had been admitted to was the one his father had given up for her.
    - name: Order of time
      description: Why do we remember the past, not the future? What does the "passage" of time mean? Do we exist in time, or does time exist in us? CarloΒ·Rowe uses poetic words to invite us to think about this ancient problem - the essence of time.
    - name: Great me
      description: How to form a new habit? How to make the mind more mature? How to have a high quality relationship? How to get out of the difficult times of life?

5.1. @ Value (common)

Use @Value("${property}") to read simple configuration information:

@Value("${wuhan2020}")
String wuhan2020;

5.2. @ Configurationproperties (common)

Read the configuration information through @ConfigurationProperties and bind it to the bean.

@Component
@ConfigurationProperties(prefix = "library")
class LibraryProperties {
    @NotEmpty
    private String location;
    private List<Book> books;

    @Setter
    @Getter
    @ToString
    static class Book {
        String name;
        String description;
    }
  ellipsis getter/setter
  ......
}

You can inject it into your classes just as you would a normal Spring bean.

5.3. PropertySource (not commonly used)

@PropertySource reads the specified properties file

@Component
@PropertySource("classpath:website.properties")

class WebSite {
    @Value("${url}")
    private String url;

  ellipsis getter/setter
  ......
}

See my article for more information:< How can SpringBoot gracefully read the configuration file in 10 minutes?> .

6. parameter verification

It goes without saying the importance of data verification. Even when the front end verifies the data, we still need to verify the data transferred to the back end again to avoid users bypassing the browser and directly requesting some illegal data from the back end through some HTTP tools.

JSR(Java Specification Requests) is a set of JavaBean parameter verification standards. It defines many commonly used verification annotations. We can directly add these annotations to our JavaBean properties, so that we can verify when verification is required. It is very convenient!

We actually use the Hibernate Validator framework for verification. Hibernate Validator is the original data validation framework of Hibernate team. Hibernate Validator 4 X is the reference implementation of Bean Validation 1.0 (JSR 303), and Hibernate Validator 5 X is the reference implementation of Bean Validation 1.1 (JSR 349). At present, the latest version of Hibernate Validator 6 X is the reference implementation of Bean Validation 2.0 (JSR 380).

There is already a hibernate validator package in the spring boot starter web dependency of the SpringBoot project, so it is not necessary to reference the relevant dependency. As shown in the following figure (generated by idea plug-in Maven Helper):

[external link image transfer failed. The source station may have an anti-theft chain mechanism. It is recommended to save the image and upload it directly (img-4dw9igig-1617893998923) (f:/typera/imgs/c7bacd12-1c1a-4e41-aaaf-4cad840fc073.png)]

Non SpringBoot projects need to introduce related dependency packages by themselves. I won't explain them here. For details, please see my article:< How to verify parameters in Spring/Spring Boot? All you need to know is here!>.

πŸ‘‰ Note: for all annotations, it is recommended to use JSR annotations, namely javax validation. Constraints, not org hibernate. validator. constraints

6.1. Some common field validation comments

  • @NotEmpty the annotated string cannot be null or empty
  • @NotBlank the annotated string is not null and must contain a non white space character
  • @Null annotated element must be null
  • @NotNull annotated element must not be null
  • @AssertTrue annotated element must be true
  • @AssertFalse annotated element must be false
  • @Pattern(regex=,flag=) the annotated element must conform to the specified regular expression
  • @Email annotated elements must be in email format.
  • @Min(value) the annotated element must be a number whose value must be greater than or equal to the specified minimum value
  • @Max(value) the annotated element must be a number whose value must be less than or equal to the specified maximum value
  • @DecimalMin(value) the annotated element must be a number whose value must be greater than or equal to the specified minimum value
  • @DecimalMax(value) the annotated element must be a number whose value must be less than or equal to the specified maximum value
  • @Size(max=, min=) the size of the annotated element must be within the specified range
  • @Digits (integer, fraction) the annotated element must be a number and its value must be within an acceptable range
  • @Past annotated element must be a past date
  • @Future the annotated element must be a future date
  • ...

6.2. Verify the requestbody

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Person {

    @NotNull(message = "classId Cannot be empty")
    private String classId;

    @Size(max = 33)
    @NotNull(message = "name Cannot be empty")
    private String name;

    @Pattern(regexp = "((^Man$|^Woman$|^UGM$))", message = "sex Value is not in optional range")
    @NotNull(message = "sex Cannot be empty")
    private String sex;

    @Email(message = "email Incorrect format")
    @NotNull(message = "email Cannot be empty")
    private String email;

}

We added the @Valid annotation to the parameters to be verified. If the verification fails, it will throw a MethodArgumentNotValidException.

@RestController
@RequestMapping("/api")
public class PersonController {

    @PostMapping("/person")
    public ResponseEntity<Person> getPerson(@RequestBody @Valid Person person) {
        return ResponseEntity.ok().body(person);
    }
}

6.3. Verify request parameters (Path Variables and Request Parameters)

Don't forget to add the Validated annotation to the class. This parameter can tell Spring to verify method parameters.

@RestController
@RequestMapping("/api")
@Validated
public class PersonController {

    @GetMapping("/person/{id}")
    public ResponseEntity<Integer> getPersonByID(@Valid @PathVariable("id") @Max(value = 5,message = "exceed id The scope of") Integer id) {
        return ResponseEntity.ok().body(id);
    }
}

For more information on how to verify parameters in a Spring project, see< How to verify parameters in Spring/Spring Boot? All you need to know is here! >This article.

7. handle Controller layer exceptions globally

Let's introduce the necessary global handling Controller layer exceptions for our Spring project.

Relevant notes:

  1. @ControllerAdvice: annotation defines the global exception handling class
  2. @ExceptionHandler: annotation declares exception handling methods

How to use it? Take the parameter verification in Section 5 as an example. If the method parameters are incorrect, a MethodArgumentNotValidException will be thrown. Let's handle this exception.

@ControllerAdvice
@ResponseBody
public class GlobalExceptionHandler {

    /**
     * Request parameter exception handling
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public ResponseEntity<?> handleMethodArgumentNotValidException(MethodArgumentNotValidException ex, HttpServletRequest request) {
       ......
    }
}

For more information on Spring Boot exception handling, please see my two articles:

  1. Several common postures of SpringBoot handling exceptions
  2. Use enumeration to simply encapsulate an elegant Spring Boot global exception handling!

8. JPA related

8.1. Create table

@Entity declares that a class corresponds to a database entity.

@Table set table name

@Entity
@Table(name = "role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String description;
    ellipsis getter/setter......
}

8.2. Create primary key

@Id: declares a field as a primary key.

After using the @Id declaration, we also need to define the generation policy of the primary key. We can use @GeneratedValue to specify the primary key generation policy.

1. specify the primary key generation policy through @GeneratedValue by directly using the four primary key generation policies provided in JPA.

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

JPA uses enumeration to define the common primary key generation strategies in 4, as follows:

Brother Guide: a use of enumerations to replace constants

public enum GenerationType {

    /**
     * Use a specific database table to save the primary key
     * The persistence engine generates the primary key through a specific table in the relational database,
     */
    TABLE,

    /**
     *In some databases, primary key self growth is not supported. For example, Oracle and PostgreSQL provide a mechanism called "sequence" to generate primary keys
     */
    SEQUENCE,

    /**
     * Primary key self growth
     */
    IDENTITY,

    /**
     *Give the primary key generation policy to the persistence engine,
     *The persistence engine will select one of the above three primary key generation strategies according to the database
     */
    AUTO
}

@The default policy used by the GeneratedValue annotation is generationtype AUTO

public @interface GeneratedValue {

    GenerationType strategy() default AUTO;
    String generator() default "";
}

Generally, if MySQL database is used, generationtype The identity policy is more common (for distributed systems, the use of Distributed ID S should be considered separately).

2. declare a primary key policy through @GenericGenerator, and then @GeneratedValue uses this policy

@Id
@GeneratedValue(generator = "IdentityIdGenerator")
@GenericGenerator(name = "IdentityIdGenerator", strategy = "identity")
private Long id;

Equivalent to:

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

The primary key generation strategies provided by jpa are as follows:

public class DefaultIdentifierGeneratorFactory
		implements MutableIdentifierGeneratorFactory, Serializable, ServiceRegistryAwareService {

	@SuppressWarnings("deprecation")
	public DefaultIdentifierGeneratorFactory() {
		register( "uuid2", UUIDGenerator.class );
		register( "guid", GUIDGenerator.class );			// can be done with UUIDGenerator + strategy
		register( "uuid", UUIDHexGenerator.class );			// "deprecated" for new use
		register( "uuid.hex", UUIDHexGenerator.class ); 	// uuid.hex is deprecated
		register( "assigned", Assigned.class );
		register( "identity", IdentityGenerator.class );
		register( "select", SelectGenerator.class );
		register( "sequence", SequenceStyleGenerator.class );
		register( "seqhilo", SequenceHiLoGenerator.class );
		register( "increment", IncrementGenerator.class );
		register( "foreign", ForeignGenerator.class );
		register( "sequence-identity", SequenceIdentityGenerator.class );
		register( "enhanced-sequence", SequenceStyleGenerator.class );
		register( "enhanced-table", TableGenerator.class );
	}

	public void register(String strategy, Class generatorClass) {
		LOG.debugf( "Registering IdentifierGenerator strategy [%s] -> [%s]", strategy, generatorClass.getName() );
		final Class previous = generatorStrategyToClassNameMap.put( strategy, generatorClass );
		if ( previous != null ) {
			LOG.debugf( "    - overriding [%s]", previous.getName() );
		}
	}

}

8.3. Set field type

@Column declaration field.

Example:

Set the database field name corresponding to the attribute userName as user_name, 32 in length, not empty

@Column(name = "user_name", nullable = false, length=32)
private String userName;

Setting field types and adding default values is quite common.

Column(columnDefinition = "tinyint(1) default 1")
private Boolean enabled;

8.4. Specify that specific fields are not persisted

@Transient: declare the fields that do not need to be mapped to the database, and do not need to be saved into the database when saving.

If we want the secrect field not to be persisted, we can use the @Transient keyword to declare it.

Entity(name="USER")
public class User {

    ......
    @Transient
    private String secrect; // not persistent because of @Transient

}

In addition to the @Transient keyword declaration, the following methods can be used:

static String secrect; // not persistent because of static
final String secrect = "Satish"; // not persistent because of final
transient String secrect; // not persistent because of transient

Generally, there are many ways to use annotations.

8.5. Declare large fields

@Lob: declare a field as a large field.

@Lob
private String content;

More detailed statement:

@Lob
//Specify the acquisition policy for Lob type data, fetchtype Eagle indicates non deferred loading, while fetchtype Lazy means delayed loading;
@Basic(fetch = FetchType.EAGER)
//The columnDefinition property specifies the Lob field type corresponding to the data table
@Column(name = "content", columnDefinition = "LONGTEXT NOT NULL")
private String content;

8.6. Create field of enum type

You can use Enumerated fields, but the Enumerated fields should be decorated with the @Enumerated annotation.

public enum Gender {
    MALE("Male"),
    FEMALE("female sex");

    private String value;
    Gender(String str){
        value=str;
    }
}
@Entity
@Table(name = "role")
public class Role {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private String description;
    @Enumerated(EnumType.STRING)
    private Gender gender;
    ellipsis getter/setter......
}

MAIL/FEMAIL is stored in the database.

8.7. Add audit function

The following four fields are added by default to any class that inherits AbstractAuditBase.

@Data
@AllArgsConstructor
@NoArgsConstructor
@MappedSuperclass
@EntityListeners(value = AuditingEntityListener.class)
public abstract class AbstractAuditBase {

    @CreatedDate
    @Column(updatable = false)
    @JsonIgnore
    private Instant createdAt;

    @LastModifiedDate
    @JsonIgnore
    private Instant updatedAt;

    @CreatedBy
    @Column(updatable = false)
    @JsonIgnore
    private String createdBy;

    @LastModifiedBy
    @JsonIgnore
    private String updatedBy;
}

The corresponding configuration classes of our corresponding audit functions may be as follows (Spring Security project):

@Configuration
@EnableJpaAuditing
public class AuditSecurityConfiguration {
    @Bean
    AuditorAware<String> auditorAware() {
        return () -> Optional.ofNullable(SecurityContextHolder.getContext())
                .map(SecurityContext::getAuthentication)
                .filter(Authentication::isAuthenticated)
                .map(Authentication::getName);
    }
}

Briefly introduce some notes designed above:

  1. @CreatedDate: indicates that this field is the creation time field. When this entity is insert ed, the value will be set

  2. @CreatedBy: indicates that this field is the creator. When this entity is insert ed, the value will be set

    @The same is true for LastModifiedDate and @LastModifiedBy.

@EnableJpaAuditing: enables JPA auditing.

8.8. Delete / modify data

@The Modifying annotation prompts JPA that this operation is a modification operation. Note that it should also be used in conjunction with the @Transactional annotation.

@Repository
public interface UserRepository extends JpaRepository<User, Integer> {

    @Modifying
    @Transactional(rollbackFor = Exception.class)
    void deleteByUserName(String userName);
}

8.9. Association relationship

  • @OneToOne declares a one-to-one relationship
  • @OneToMany declares a one to many relationship
  • @ManyToOne declares many to one relationship
  • MangToMang declares many to many relationships

For more articles on Spring Boot JPA, please see my article: How to correctly use JPA in Spring Boot .

9. transaction @Transactional

Use the @Transactional annotation on the method to start the transaction!

@Transactional(rollbackFor = Exception.class)
public void save() {
  ......
}

We know that exceptions can be divided into runtimeexceptions and non runtime exceptions. If the rollback for attribute is not configured in the @Transactional annotation, the transaction will only be rolled back when it encounters a RuntimeException. Add rollback for=Exception Class, which allows things to roll back when encountering non runtime exceptions.

@Transactional annotations are generally used to act on classes or methods.

  • Apply to class: when the @Transactional annotation is placed on a class, it means that all public methods of the class are configured with the same transaction attribute information.
  • Action on method: when a class is configured with @Transactional and a method is configured with @Transactional, the transaction of the method will overwrite the transaction configuration information of the class.

For more information about Spring transactions, please see:

  1. Perhaps the most beautiful Spring transaction management explanation
  2. Say six @Transactional annotation invalidation scenarios at one go

10. json data processing

10.1. Filter json data

@JsonIgnoreProperties acts on a class to filter out specific fields that are not returned or resolved.

//Filter the userRoles attribute when generating json
@JsonIgnoreProperties({"userRoles"})
public class User {

    private String userName;
    private String fullName;
    private String password;
    @JsonIgnore
    private List<UserRole> userRoles = new ArrayList<>();
}

@JsonIgnore is generally used for class properties, and its function is the same as @JsonIgnoreProperties above.

public class User {

    private String userName;
    private String fullName;
    private String password;
   //Filter the userRoles attribute when generating json
    @JsonIgnore
    private List<UserRole> userRoles = new ArrayList<>();
}

10.2. Format json data

@JsonFormat is generally used to format json data.:

For example:

@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="yyyy-MM-dd'T'HH:mm:ss.SSS'Z'", timezone="GMT")
private Date date;

10.3. Flatten object

@Getter
@Setter
@ToString
public class Account {
    @JsonUnwrapped
    private Location location;
    @JsonUnwrapped
    private PersonInfo personInfo;

  @Getter
  @Setter
  @ToString
  public static class Location {
     private String provinceName;
     private String countyName;
  }
  @Getter
  @Setter
  @ToString
  public static class PersonInfo {
    private String userName;
    private String fullName;
  }
}

Before flattening:

{
    "location": {
        "provinceName":"Hubei",
        "countyName":"Wuhan"
    },
    "personInfo": {
        "userName": "coder1234",
        "fullName": "shaungkou"
    }
}

After flattening the object with @JsonUnwrapped:

@Getter
@Setter
@ToString
public class Account {
    @JsonUnwrapped
    private Location location;
    @JsonUnwrapped
    private PersonInfo personInfo;
    ......
}
{
  "provinceName":"Hubei",
  "countyName":"Wuhan",
  "userName": "coder1234",
  "fullName": "shaungkou"
}

11. test related

@ActiveProfiles generally act on test classes to declare valid Spring configuration files.

@SpringBootTest(webEnvironment = RANDOM_PORT)
@ActiveProfiles("test")
@Slf4j
public abstract class TestBase {
  ......
}

@Test declares a method as a test method

@The data of the declared test method of Transactional will be rolled back to avoid polluting the test data.

@Provided by WithMockUser Spring Security, it is used to simulate a real user and can be granted permissions.

    @Test
    @Transactional
    @WithMockUser(username = "user-id-18163138155", authorities = "ROLE_TEACHER")
    void should_import_student_success() throws Exception {
        ......
    }

IOC

Dependency injection

Let the dependency of the calling class on an interface implementation class be injected by a third party (container or collaboration class) to remove the dependency of the calling class on an interface implementation class

Injection mode

  • Constructor Inject
  • Attribute injection
  • Factory method injection
  • Interface injection (the same as attribute injection, which is not supported by Spring)

Implementation principle

  • Using Java reflection technology
  • Reflection related class
    • ​ ClassLoader
    • ​ Class
    • ​ Constructor
    • ​ Method
    • ​ Field
  • Class loader
    • Working mechanism

      • Loading: finding and importing Class documents

      • link

        • test
        • prepare
        • analysis
      • Initialization: initializes static variables and static code blocks of a class

    • ClassLoader

      • ClassLoader (root loader): loads the core class libraries under the JRE directory

      • ExtClassLoader: loads the JAR class package of the JRE extension directory ext

      • AppClassLoader: loads class packages under Classpath

SpringBean

Bean scope
  1. singleton
    1. singleton: singleton mode (unsafe under multithreading)

      • singleton: singleton mode. There will only be one shared Bean instance in the Spring IoC container, no matter how many

        The Bean refers to it and always points to the same object. This mode is not safe in multithreading. Singleton scope is

        The default scope in Spring can also be displayed to define beans as singleton patterns, which are configured as follows:

  2. prototype
    1. Prototype: prototype mode is created each time it is used

      • Prototype: prototype pattern. Each time you get the bean defined by the prototype through the Spring container, the container will create

        A new Bean instance. Each Bean instance has its own properties and state, while the singleton global has only one pair

        Elephant. As a rule of thumb, use the prototype scope for stateful beans and singleton for stateless beans

        Scope.

  3. request (Web environment specific)
    1. Request: request one instance at a time

      • Request: in an Http request, the container will return the same instance of the Bean. For different Http requests

        A new bean is generated, and the bean is only valid in the current Http Request. The current Http Request ends, and the bean

        The instance will also be destroyed.

  4. session (unique to Web environment)
    • Session: in an Http Session, the container will return the same instance of the Bean. For different sessions, please

      A new instance will be created. The bean instance is only valid in the current Session. Same as Http request, every time

      The session requests to create a new instance, but different instances do not share attributes, and the instance is only in its own session request

      If the request ends, the instance will be destroyed.

  5. global session (unique to Web environment)
    1. global Session: in a global Http Session, the container will return the same instance of the Bean. Only in the

      Valid when using portlet context.

Control reversal

IOC is called inversion of control. It refers to managing the creation, configuration, and lifecycle of objects through Spring

It is equivalent to handing over control to spring, which does not require manual management of complex dependencies between objects

The advantage is to use HashMap for storage

Underlying principle

1. In a simple sentence: Factory + reflection + configuration file

2. Details

2.1 xml parsing get the full pathname of the class from the xml configuration file <bean id = "userdao" class= "com.xxx.userdao" / >

2.2 create objects using reflection mechanism

​ Class clazz = Class.forName("full pathname of class")

​ Object object = clazz.newInstance();

2.3 use factory mode to return objects (the bottom layer of IOC container is the object factory)

Two IOC core containers

BeanFactory

  1. BeanFactory is the infrastructure of Spring framework, which is oriented to Spring itself;

    ApplicationContext is for developers who use the Spring framework. In almost all applications, we directly use ApplicationContext instead of the underlying BeanFactory.

  2. BeanFactory top level interface

    1. Located at the top of the class structure tree, its main method is getBean (String beanName). This method returns a Bean BeanFactory with a specific name from the container. Its function is continuously expanded through other interfaces
  3. SingletonBeanResitry registering a singleton Bean during runtime

    Defines the method of registering a singleton Bean with the container during the permission period; For singleton beans, BeanFactory caches Bean instances, so the second time getBean is used to obtain beans, it will directly obtain Bean instances from the cache of IoC container. Spring provides a buffer for caching single instance beans in the defaultsingletonbeanrestore class, which is implemented with HashMap

  4. Dependency log management plug-in

    When initializing BeanFactory, a logging framework must be provided for it, such as log4j and slf4j, so that no error will be reported during startup

  5. Difference between top-level interface BeanFactory and ApplicationContext

    • Applicable to singleton objects
      • When ApplicationContext builds the core container, the object is created by loading immediately, that is, the object is created immediately after the configuration file is read
    • Applicable to multiple objects
      • BeanFactory uses the method of delayed loading when building core objects, that is, when to obtain objects through Id and when to create them

ApplicationContext

ApplicationContext common implementation classes
  1. ClassPathXmlApplicationContext reads the configuration file under the classpath
  2. FileSystemXmlApplicationContext reads configuration files from anywhere on the computer
  3. AnnotationConfigApplicationContext is used to replace the xml configuration file with a new annotation + configuration class

WebApplication architecture

It is specially prepared for web applications. It allows loading configuration files from the path relative to the web root directory to complete initialization. The reference of ServletContext can be obtained from the WebApplicationContext. The entire web application context object will be placed in the ServletContext as an attribute so that the web application environment can access the Spring context application.

Four methods of Spring dependency injection DI

Constructor Injection

  1. Must have constructor
  2. bean label lower label
    1. Name: attribute name
    2. Value: value, for basic type and String
    3. ref: for object type
/*With parameters, it is convenient to inject with the constructor*/
public  CatDaoImpl(String message){
    this.message=message;
}
<bean id="CatDaoImpl" class="co m.CatDaoImpl">
    <constructor-arg value="message"></constructor-arg>
    </bean>

setter method

  1. Condition: property must have a setter method
  2. bean label lower label
    1. Name: attribute name
    2. Value: attribute value, for basic attribute and String type
    3. ref: for object type, it refers to the value of id attribute of bena tag
public class Id{
    private int id;
    public int getId(){
        return id;
    }
    public void setId(int Id){
        this.id = id;
    }
    <bean id="id" class="com.id"><property name ="id" value = "123"></property></bean>
}

Static factory injection

  1. Static factory: as the name suggests, it is to obtain the objects we need by calling the methods of the static factory. In order to let spring manage all objects, we cannot directly use * * engineering classes Static method () * * to obtain the object, but still through spring injection
  2. Condition: factory class is required, and static methods are required in this factory class
    1. Configuration file syntax <bean id = factory class = "com.zzub.factory.beanfactory" factory method= "static method name" / >
    2. When the getBean method is called with the spring container, the factory class object will be created, and the method in the factory class will be executed to return the corresponding object and put it into the spring container.
public class DaoFactory { //Static factory

public static final FactoryDao getStaticFactoryDaoImpl(){

return new StaticFacotryDaoImpl();

}

}

public class SpringAction {

private FactoryDao staticFactoryDao; //Injection object

//set method of injection object

public void setStaticFactoryDao(FactoryDao staticFactoryDao) {

this.staticFactoryDao = staticFactoryDao;

}

}

//Factory method= "getstaticfactorydaoimpl" specify which factory method to call

<bean name="springAction" class=" SpringAction" >

<!--Injecting objects using static factory methods,Corresponding to the following configuration file-->

<property name="staticFactoryDao" ref="staticFactoryDao"></property>

</bean>

<!--The way to get the object here is to get the static method from the factory class-->

<bean name="staticFactoryDao" class="DaoFactory"

factory-method="getStaticFactoryDaoImpl"></bean>

Instance factory

The instance factory means that the method to obtain the object instance is not static, so you need to first create the new factory class, and then call the normal

  1. Condition: a factory class is required. This factory class needs to have common methods
  2. Configuration file syntax
    1. You need to create a factory object before calling the normal methods in the factory.

Instance method

public class DaoFactory { //Instance factory

public FactoryDao getFactoryDaoImpl(){

return new FactoryDaoImpl();
}

}

public class SpringAction {

private FactoryDao factoryDao; //Injection object

public void setFactoryDao(FactoryDao factoryDao) {

this.factoryDao = factoryDao;

}

}

<bean name="springAction" class="SpringAction">

<!--Injecting objects using the methods of the instance factory,Corresponding to the following configuration file-->

<property name="factoryDao" ref="factoryDao"></property>

</bean>

<!--The way to get the object here is to get the instance method from the factory class-->

<bean name="daoFactory" class="com.DaoFactory"></bean>

<bean name="factoryDao" factory-bean="daoFactory"

factory-method="getFactoryDaoImpl"></bean>

Common methods for IOC development

Fully automatic configuration mode

  1. Basically no configuration file
  2. Use the @Component annotation on the class to mark the dependencies in the class. Use the @Autowired annotation to mark
  3. Use @MapperScan annotation
  4. **Note that if a type matches multiple implementation classes, you must use the @Qualifier annotation to specify the required classes
  5. Four annotations for creating objects
    1. @When the Component cannot be divided into classes
    2. @The general user of a Repository annotates the Dao(Mapper) layer or the database operation layer
    3. @Service business layer
    4. @Controller control layer / presentation layer
  6. Annotations for three dependency injections
    1. @Value for basic data type and String type
    2. @Autowired
      1. This annotation is provided by the Spring framework
      2. Search by type. If you can't find it, it means No. if you find more than one, an error will be reported. The solution is to use the @Qualifier annotation to indicate which annotation to use
    3. @Resource
      1. This annotation is provided by JDK
      2. First, search by name. The first is the name attribute configuration name @Resource(name= "name"). If no name is specified, the variable name will be regarded as the attribute name to be searched. If it cannot be found again, finally, search by type.

AOP

Face tangent plane

  • AOP is called aspect oriented programming. Its purpose is to implant new functions into the program without modifying the original code, so as to improve the modularity of the code

  • SpringAOP is implemented based on dynamic proxy. If it is an interface, JDK dynamic proxy will be used. Otherwise, CGLIB will be used

    • JDK dynamic proxy: implements the interface. java reflection mechanism generates an anonymous class of proxy interface. invokeHandler is called when calling specific methods
    • CGLIB loads based on ClassLoad and modifies bytecode to generate subclasses for processing

    Benefits decoupling!

  • Underlying principle - Dynamic Proxy

    • What is the difference between a static proxy and a dynamic proxy?
      1. Each time the static proxy is enhanced, a new class will be created, and the code looks very bloated
      2. The static agent knows the object to be represented before the agent, and the dynamic agent runs until
      3. Static proxy can only proxy one class, while dynamic proxy implements multiple subclasses of the interface
    • Differences between JDK dynamic proxy and CGLIB dynamic proxy
      1. JDK dynamic proxy requires that the proxy object must implement an interface. Based on the reflection mechanism, a proxy class that implements the same interface is generated, and then implemented by rewriting methods to enhance the code
      2. If the proxy class does not implement an interface, CGLIB dynamic proxy is used to generate a subclass by modifying the bytecode based on the ASM third-party framework, and then rewrite the method of the parent class to enhance the code
      3. The performance of CGLIB before 1.8 is higher, but the performance after 1.8 is similar

Applicable scenarios

  1. Performance test
  2. access control
  3. transaction management
  4. Logging
  5. Permission control
  6. Distributed tracking
  7. Cache control

term

JoinPoint

The specific point in the process of program execution is generally the call of methods. The intercepted point. Because Spring only supports connection points of method types, connection points in Spring refer to the intercepted methods. In fact, connection points can also be fields or constructors

Target class

An object that contains a connection point. Also known as the notified or proxied object. POJO

Proxy

For the object created by AOP framework, the proxy is the reinforcement of the target object. AOP proxy in Spring can make JDK dynamic proxy or CGLIB proxy. The former is based on interface and the latter is based on subclasses.

PointCut

It is a join point with notification, which is mainly reflected in writing pointcut expressions in the program

Advice

AOP performs enhanced processing on specific pointcuts, including before, after, afterreturning, afterpassing, and around

Aspect

It is usually a class in which pointcuts and notifications can be defined

Weaving

The process of applying facets to the target object and causing the proxy object to be created

Introduction

Without modifying the code, some methods or fields can be dynamically added to the class at run time

Annotations (AspectJ framework)

  • @Aspect implements a class as facet class
  • @Before a notification is preceded, which is executed before the target execution method
  • @After post notification, execute after the target method is specified
  • @AfterReturning returns a notification that the target method is executed successfully
  • @AfterThrowing exception notification, abnormal execution of target method
  • @Surround surround notification, surround target method execution
  • @Pointcut defines a pointcut expression for other annotation references
  • @Order(1) marks the priority of the enhanced class, that is, the smaller the value, the smaller the priority

Spin transaction

The concept of transaction exists in MySQL. Transaction refers to a set of sql statements. There are many sql statements in the set, including insert, update, select and delete. We hope that these sql statements can be executed successfully or fail. These behaviors are consistent and executed as a whole

Four properties ACID

  • Atomicity: indicates that multiple database operations that make up a transaction are an indivisible atomic unit
  • Consistency: after the transaction operation is successful, the status of the database is consistent with its business rules, that is, the data will not be destroyed
  • Isolation: during concurrent database operations, different transactions have their own data spaces, and their operations will not interfere with each other
  • Durability: once the transaction is committed successfully, all data operations in the transaction must be persisted to the database

Transaction isolation level

1,read_ Uncommitted (maximum concurrency and throughput)
2,read_commited
3,repeatable_read
4. serializable (minimum concurrency)

Transaction propagation behavior

Propagation: propagation behavior (7 kinds) - @transitional (propagation=propagation.required)
  • Request (default) if there is no transaction currently, a new transaction will be created. If there is a transaction currently, the transaction will be added (most commonly used)

  • REQUIRES_NEW whether there is a transaction or not, create a new transaction to execute. If it is already in a transaction, suspend the current transaction [start transaction 2 to execute separately. If it fails, roll back your own transaction 1. If it fails, transaction 2 will not be affected]

  • SUPPORTS if a transaction currently exists, it will be added to the transaction. If no transaction currently exists, it will be executed as a non transaction

  • NOT_SUPPORTS enforces execution in a non transactional manner. If a transaction exists, the current transaction is suspended

  • MANDATORY requires transaction execution. If no transaction currently exists, an exception will be thrown

  • NEVER enforces non transactional execution. If there is a transaction, an exception is thrown

  • NESTED if there is a transaction, it will be executed within the NESTED transaction. If there is no transaction at present, it will be executed according to the REQUIRED attribute

    Nested transactions. If the outer transaction is rolled back, the inner transaction will also be rolled back;
    However, if an inner transaction is rolled back, it just rolls back its own code

Spring declarative transaction

Underlying principle AOP
1. Programming

TransactionTemplate manually writes the commit rollback logic | it is intrusive to business code

2. Declarative (based on SpringAOP Implementation)
  1. XML style

    <!--Configure transaction manager-->
    <bean id="transactionManager"
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    
    <!--combination aop Implement transaction weaving-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <tx:attributes>
            <tx:method name="*" propagation="REQUIRED"/>
        </tx:attributes>
    </tx:advice>
    
    <!--Configure transaction cut in-->
    <aop:config>
        <aop:pointcut id="txPointCut" expression="execution(...)"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
    </aop:config>
    

    1. Define data source

    2. Define transaction manager

    3. Define transaction enhancements

    4. Transaction enhancement of facets using AOP

  2. Annotative

    1. Define data source
    2. Define transaction manager
    3. Enable transaction annotation drive
    4. Use @Transaction annotation on class or method

Spring dependency loop

What is circular dependency?

Two or more bean s depend on each other to form a closed loop

public class A{
	private B b;
}
public class B{
private A a;
}

Premise for solving circular dependency

  1. Not all circular dependencies in constructor mode
  2. It must be a singleton, or it cannot be solved

Note: Spring creates objects in a distributed manner. First, it creates the target object (instantiation) and then injects attributes (initialization) into it

L3 cache

private final Map<String,Object> signletonObjects = new ConcurrentHashMap<>(256);
private final Map<String,Object> earlySingletonObjects = new HashMap<>(16);
private final Map<String,ObjectFactory<?>> singletonFactories = new HashMap<>(16);
  • singletonObjects first level cache to store available finished bean s

  • earlySingletonObjects Level 2 cache. The semi-finished Bean is a created object, but the initialization is not completed to solve the circular dependency

  • singletonFactories 3rd level cache, storing Bean factory objects

    Bean s used to generate semi-finished products and put them into the L2 cache

step

  • First, create an object A and find its dependent object B when injecting attributes. Therefore, it is necessary to inject object B
  • It is found that there is no object B in the cache. At this time, put the object A into the semi-finished product cache, and then create the object B
  • The creation of the B object depends on the A object, so the semi-finished product A is taken from the semi-finished product cache for injection
  • B object continues to inject other attributes and initialization, and then puts the finished product B object into the finished product cache
  • Object A continues to inject attributes, fetches object B of finished product from finished product cache and injects
  • Object A continues to inject other attributes and initialization, and then puts the finished product A object into the finished product cache

Little Question

Must I use L3 cache to resolve circular dependencies? Can I use L2 cache only?

No, it violates the design principles of Spring

If the L2 cache is used to solve the circular dependency, it means that the Bean creates the proxy object after construction, which violates the spring design principles Spring combines the declaration cycle of AOP and Bean. After the Bean is created, it is completed through the post processor AnnotationAwareAspectJAutoProxyCreator. In the post-processing postProcessAfterInitialization method, the AOP proxy is completed for the initialized Bean. If there is a circular dependency, there is no way but to create an agent for the Bean first. But if there is no circular dependency, the design is to let the Bean complete the agent at the last step of the life cycle, rather than immediately complete the agent after instantiation

L3 cache summary

  1. Attribute injection can be cracked
  2. The constructor doesn't work. The L3 cache doesn't have its own, because the L2 cache loads B
  3. L3 cache
    1. Go to the single case pool
    2. Determine whether it is being created
    3. Determine whether circular dependency is supported
    4. L2 cache to L3 cache
    5. Kill L2 cache GC
    6. Next time, I'll take it directly from the L3 cache. Cache it
  4. Cache storage
    1. L1 cache singleton Bean
    2. L2 cache factory generates Bean complex
    3. L3 cache semi-finished product

Some small problems and pits

1. Are beans in Spring thread safe?

  1. Prototype Bean
    1. Every time an object is created, it is thread safe
  2. Singleton Bean
    1. Depending on the specific situation, a stateless Bean is thread safe
    2. Thread safety problems may occur in multithreading when there are member variables
    3. If you do not want to use shared variables, you can use ThreadLocal

2. Is the Controller in the Spring framework a singleton?

  1. The Controller is singleton by default, which does not guarantee thread safety, and its attributes will be reused

  2. How to solve??

    1. Do not define member variables in the controller

    2. You can set it to multi instance mode through @Scope("property")

    3. Using ThreadLocal in the controller layer

Tags: Java Spring Spring Boot Annotation

Posted by deljhp on Thu, 02 Jun 2022 22:07:39 +0530