Spring learning notes, IOC to DI, dynamic proxy to AOP

Posted by robertvideo on Sat, 09 Oct 2021 06:42:51 +0200

1. IOC(Inversion of Control)

Review the MVC three-tier architecture

The user's operation on the interface (view layer) is actually going to the operation Controller layer to call the service layer, and the service completes the methods and operations defined in the Dao layer by creating (New) the relevant entity class objects of the Dao layer.

If users have many needs and different objects have different methods, object-oriented, it is troublesome to re create new objects and call methods in the service layer every time. It is necessary to reduce the operation on the service layer. The operation authority should be directly placed in the Controller layer controlled by the user.

If the above objects exist in many implementation classes, they have strong coupling, and there are many places that need to be modified manually. Therefore, one thing is needed to manage and generate objects uniformly. This thing is the IOC container. Through the injection of the set method, each time the requirements are modified, the user only needs to enter an implementation class name to create the corresponding objects and modify them And call the method, so that the control is transferred from the programmer to the user, and the programmer does not need to modify a lot of code each time. This realizes the understanding of coupling and realizes IOC

Control inversion is a way to produce or obtain specific objects through description (XML or annotation) and through a third party. In Spring, IoC container implements control inversion, and its implementation method is dependency injection (DI).

2.Hello Spring

2.1 import jar package

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>spring-study</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>spring-02-hellospring</module>
    </modules>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
    </dependencies>
</project>

2.2 create beans.xml file as a container for creating objects

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--use Spring To create an object, in Spring These are called Bean-->
    <!--bean namely java object , from Spring Create and manage-->
    <bean id="hello" class="com.chang.pojo.Hello">
        <property name="str" value="Hello Spring"/>
    </bean>

</beans>

2.3 writing entity classes and test classes

Hello entity class

package com.chang.pojo;

public class Hello {
    private String str;

    public String getStr() {
        return str;
    }

    public void setStr(String str) {
        this.str = str;
    }

    @Override
    public String toString() {
        return "Hello{" +
                "str='" + str + '\'' +
                '}';
    }
}

Test class

import com.chang.pojo.Hello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.lang.management.GarbageCollectorMXBean;

public class MyTest {
    public static void main(String[] args) {
        //Get the context object of Spring
        ApplicationContext context =  new ClassPathXmlApplicationContext("beans.xml");
        //Objects are now managed in Spring. If you want to use them, you can get them directly.
        // The new object is not needed. It is left to the container to implement the control inversion
        Hello hello =(Hello) context.getBean("hello");
        System.out.println(hello.toString());

    }
}

It is equivalent to taking the object directly from the beans.xml container

Get results

3.IOC object creation method







3.1. Create by parameterless construction method

1,User.java

public class User {

   private String name;

   public User() {
       System.out.println("user Nonparametric construction method");
  }

   public void setName(String name) {
       this.name = name;
  }

   public void show(){
       System.out.println("name="+ name );
  }

}

2,beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="user" class="com.kuang.pojo.User">
       <property name="name" value="kuangshen"/>
   </bean>

</beans>

3. Test class

@Test
public void test(){
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   //When the getBean is executed, the user has been created and constructed without parameters
   User user = (User) context.getBean("user");
   //Call the method of the object
   user.show();
}

As a result, it can be found that the User object has been initialized through parameterless construction before calling the show method!







4.2. Create by parametric construction method

1,UserT . java

public class UserT {

   private String name;

   public UserT(String name) {
       this.name = name;
  }

   public void setName(String name) {
       this.name = name;
  }

   public void show(){
       System.out.println("name="+ name );
  }

}

2. beans.xml can be written in three ways

<!-- First basis index Parameter subscript setting -->
<bean id="userT" class="com.kuang.pojo.UserT">
   <!-- index Refers to the construction method , Subscript starts at 0 -->
   <constructor-arg index="0" value="kuangshen2"/>
</bean>
<!-- The second is set according to the parameter name -->
<bean id="userT" class="com.kuang.pojo.UserT">
   <!-- name Refers to the parameter name -->
   <constructor-arg name="name" value="kuangshen2"/>
</bean>
<!-- The third is set according to the parameter type -->
<bean id="userT" class="com.kuang.pojo.UserT">
   <constructor-arg type="java.lang.String" value="kuangshen2"/>
</bean>

3. Testing

@Test
public void testT(){
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   UserT user = (UserT) context.getBean("userT");
   user.show();
}

Conclusion: when the configuration file is loaded, the managed objects have been initialized!

5.Spring configuration







5.1. Alias

Alias sets an alias for a bean. You can set multiple aliases

<!--Setting alias: getting Bean You can use alias to get-->
<alias name="userT" alias="userNew"/>







5.2.Bean configuration

<!--bean namely java object,from Spring Create and manage-->

<!--
   id yes bean Identifier of,To be unique,If not configured id,name Is the default identifier
   If configured id,Configured again name,that name It's an alias
   name You can set multiple aliases,You can use commas,semicolon,Space separated
   If not configured id and name,Can be based on applicationContext.getBean(.class)Get object;

class yes bean Fully qualified name of=Package name+Class name
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
   <property name="name" value="Spring"/>
</bean>







5.3.import

Team cooperation is achieved through import

When there are multiple beans.xml files, you should pass in the test class

ApplicationContext context = new classpathxmlapplicationcontext ("beans. xml"); it will be troublesome to import, so you can only import one xml file. Just add the following import to this xml file
<import resource="{path}/beans.xml"/>
<import resource="{path}/beans2.xml"/>
<import resource="{path}/beans3.xml"/>

Different classes are sometimes registered in different bean s and developed by different people, so import is required

6. Dependency injection (DI)

Dependency Injection

concept

  • Dependency injection (DI).

  • Dependency: the creation of a Bean object depends on the container. The dependent resources of a Bean object

  • Injection: refers to the resources that the Bean object depends on, which are set and assembled by the container





6.1. Constructor injection   

Constructor Injection

We have already talked about the case before





6.2.Set injection (key) attribute injection

Set injection (key)

The attribute to be injected must have a set method. The method name of the set method is capitalized by the initial letter of set + attribute  

Test pojo class:

Address.java

 public class Address {
 
     private String address;
 
     public String getAddress() {
         return address;
    }
 
     public void setAddress(String address) {
         this.address = address;
    }
 }

Student.java

 package com.kuang.pojo;
 
 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;
 
 public class Student {
 
     private String name;
     private Address address;
     private String[] books;
     private List<String> hobbys;
     private Map<String,String> card;
     private Set<String> games;
     private String wife;
     private Properties info;
 
     public void setName(String name) {
         this.name = name;
    }
 
     public void setAddress(Address address) {
         this.address = address;
    }
 
     public void setBooks(String[] books) {
         this.books = books;
    }
 
     public void setHobbys(List<String> hobbys) {
         this.hobbys = hobbys;
    }
 
     public void setCard(Map<String, String> card) {
         this.card = card;
    }
 
     public void setGames(Set<String> games) {
         this.games = games;
    }
 
     public void setWife(String wife) {
         this.wife = wife;
    }
 
     public void setInfo(Properties info) {
         this.info = info;
    }
 
     public void show(){
         System.out.println("name="+ name
                 + ",address="+ address.getAddress()
                 + ",books="
        );
         for (String book:books){
             System.out.print("<<"+book+">>\t");
        }
         System.out.println("\n hobby:"+hobbys);
 
         System.out.println("card:"+card);
 
         System.out.println("games:"+games);
 
         System.out.println("wife:"+wife);
 
         System.out.println("info:"+info);
 
    }
 }





6.3. Extended injection

1. Constant injection

 <bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="Xiao Ming"/>
 </bean>

Test:

 @Test
 public void test01(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
 
     Student student = (Student) context.getBean("student");
 
     System.out.println(student.getName());
 
 }

2. Bean injection

Note: the value here is a reference, ref

If the injected variables are of a class type, you need to use ref = "class name"

 <bean id="addr" class="com.kuang.pojo.Address">
     <property name="address" value="Xi'an"/>
 </bean>
 
 <bean id="student" class="com.kuang.pojo.Student">
     <property name="name" value="Xiao Ming"/>
     <property name="address" ref="addr"/>
 </bean>

3. Array injection

 <bean id="student" class="com.kuang.pojo.Student">
     <property name="books">
         <array>
             <value>Journey to the West</value>
             <value>The Dream of Red Mansion</value>
             <value>Water Margin</value>
         </array>
     </property>
 </bean>

4. List injection

 <property name="hobbys">
     <list>
         <value>listen to the music</value>
         <value>watch movie</value>
         <value>Mountain climbing</value>
     </list>
 </property>

5. Map injection

 <property name="card">
     <map>
         <entry key="ID" value="610549848465145454"/>
         <entry key="Bank card No" value="6548946541546546545"/>
     </map>
 </property>

6. set injection

 <property name="games">
     <set>
         <value>LOL</value>
         <value>BOB</value>
         <value>COC</value>
     </set>
 </property>

7. Null injection

 <property name="wife"><null/></property>

8. Properties injection

 <property name="info">
     <props>
         <prop key="Student number">20190604</prop>
         <prop key="Gender">male</prop>
         <prop key="full name">Xiao Ming</prop>
     </props>
 </property>

9. p named and c named injection

p naming is equivalent to the simplification of set attribute injection

c named injection is equivalent to the simplification of constructor injection. There needs to be a constructor with parameters.

User.java :

 public class User {
     private String name;
     private int age;

    public User(String name,int age){
        this.name=name;
        this.age=age;
}
 
     public void setName(String name) {
         this.name = name;
    }
 
     public void setAge(int age) {
         this.age = age;
    }
 
     @Override
     public String toString() {
         return "User{" +
                 "name='" + name + '\'' +
                 ", age=" + age +
                 '}';
    }
 }

1. P namespace injection: a constraint file needs to be added to the header file

 Import constraints : xmlns:p="http://www.springframework.org/schema/p"
 
 <!--P(attribute: properties)Namespace , Direct injection attribute-->
 <bean id="user" class="com.kuang.pojo.User" p:name="Mad God" p:age="18"/>

P namespace injection is equivalent to < property name = "" / >       p:(property:)

You can inject the value of the attribute directly

2. c namespace injection: constraint files need to be added to the header file

 Import constraints : xmlns:c="http://www.springframework.org/schema/c"
 <!--C(structure: Constructor)Namespace , Using constructor injection-->
 <bean id="user" class="com.kuang.pojo.User" c:name="Mad God" c:age="18"/>

c is the so-called constructor injection!

Test code:

 @Test
 public void test02(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     User user = (User) context.getBean("user");
     System.out.println(user);
 }

6.4. Scope of bean

In Spring, the main body of the application and the objects managed by the Spring IoC container are called beans. In short, beans are objects initialized, assembled and managed by the IoC container

Among the several scopes, the request and session scopes are only used in web-based applications (don't care what web application framework you use), and can only be used in Web-based Spring ApplicationContext environment.


Singleton (singleton mode, spring's default mechanism)

When the scope of a bean is singleton, there will only be one shared bean instance in the Spring IoC container, and all requests for a bean will only return the same instance of the bean as long as the id matches the bean definition. Singleton is a singleton type, which automatically creates a bean object when creating the container. It exists whether you use it or not , the object obtained each time is the same object. Note that the singleton scope is the default scope in Spring. To define a bean as a singleton in XML, you can configure it as follows:

 <bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">

Test:

 @Test
 public void test03(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
     User user = (User) context.getBean("user");
     User user2 = (User) context.getBean("user");
     System.out.println(user==user2);
 }

Result: user==user2 is true, indicating that there is only one bean object in the singleton mode. No matter how many objects are created, they will point to the bean object automatically created when the container is created


Prototype (prototype mode)

A new object is generated every time a bean is getBean from the container

When the scope of a bean is prototype, it means that a bean definition corresponds to multiple object instances. A prototype scoped bean will cause a new bean instance to be created each time a request is made to the bean (inject it into another bean, or call the container's getBean() method programmatically). Prototype is a prototype type. It is not instantiated when we create a container. Instead, we create an object when we obtain a bean, and the object we obtain each time is not the same object. As a rule of thumb, you should use the prototype scope for stateful beans and the singleton scope for stateless beans. Define a bean as a prototype in XML, which can be configured as follows:

 <bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>  
  perhaps
 <bean id="account" class="com.foo.DefaultAccount" singleton="false"/>


The following request session application can only be used in web development.

Request

When the scope of a bean is Request, it means that in an HTTP Request, a bean definition corresponds to an instance; That is, each HTTP Request will have its own bean instance, which is created according to a bean definition. This scope is only valid in the case of web-based Spring ApplicationContext. Consider the following bean definitions:

 <bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>

For each HTTP request, the Spring container will create a new loginaction bean instance according to the loginaction bean definition, and the loginaction bean instance is only valid in the current HTTP request. Therefore, you can safely change the internal state of the created instance according to the needs, while the instances created according to the loginaction bean definition in other requests, You will not see these state changes specific to a request. When the processing of the request ends, the bean instance of the request scope will be destroyed.


Session

When the scope of a bean is Session, it means that in an HTTP Session, a bean definition corresponds to an instance. This scope is only valid in the case of web-based Spring ApplicationContext. Consider the following bean definitions:

 <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>

For an HTTP Session, the Spring container will create a new userPreferences bean instance according to the userPreferences bean definition, and the userPreferences bean is only valid in the current HTTP Session. Like the request scope, you can safely change the internal state of the created instance as needed. For instances created according to userPreferences in other HTTP sessions, you will not see these state changes specific to an HTTP Session. When the HTTP Session is finally discarded, the beans within the scope of the HTTP Session will also be discarded.

7. Automatic assembly of bean

Automatic assembly instructions

  • Automatic assembly is a way to use spring to meet bean dependencies
  • spring will find the bean that a bean depends on in the application context.

There are three assembly mechanisms for bean s in Spring:

  1. Explicit configuration in xml;
  2. Explicit configuration in java;
  3. Implicit bean discovery mechanism and automatic assembly.

Here we mainly talk about the third kind: automated assembly bean.

Spring's automatic assembly needs to be implemented from two perspectives, or two operations:

  1. Component scanning: spring will automatically discover the bean s created in the application context;
  2. Autowiring: spring automatically satisfies the dependencies between bean s, which is what we call IoC/DI;

The combination of component scanning and automatic assembly has great power to minimize the configuration of display.

It is recommended to use annotations instead of automatic assembly xml configuration

**
**

Test environment construction

1. Create a new project

2. Create two new entity classes. Cat Dog has a method called

public class Cat {
   public void shout() {
       System.out.println("miao~");
  }
}
public class Dog {
   public void shout() {
       System.out.println("wang~");
  }
}

3. Create a new User class User

public class User {
   private Cat cat;
   private Dog dog;
   private String str;
}
  • 1
  • 2
  • 3
  • 4
  • 5

4. Writing Spring configuration files

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

   <bean id="dog" class="com.kuang.pojo.Dog"/>
   <bean id="cat" class="com.kuang.pojo.Cat"/>

   <bean id="user" class="com.kuang.pojo.User">
       <property name="cat" ref="cat"/>
       <property name="dog" ref="dog"/>
       <property name="str" value="qinjiang"/>
   </bean>
</beans>

5. Testing

public class MyTest {
   @Test
   public void testMethodAutowire() {
       ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
       User user = (User) context.getBean("user");
       user.getCat().shout();
       user.getDog().shout();
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

The result is normal output and the environment is OK

7.1.byName

byName

autowire byName

In the process of manually configuring xml, errors such as missing letters and case often occur, which can not be checked, which reduces the development efficiency.

Using automatic assembly will avoid these errors and simplify the configuration.

Test:

1. Modify the bean configuration and add an attribute autowire = "byName"

<bean id="user" class="com.kuang.pojo.User" autowire="byName">
   <property name="str" value="qinjiang"/>
</bean>
  • 1
  • 2
  • 3

2. Test again and the result is still output successfully!

3. We modify the bean id of cat to catXXX

4. Test again and execute the null pointer java.lang.NullPointerException. Because the wrong set method is found according to the byName rule, the real setCat is not executed and the object is not initialized, so a null pointer error will be reported when calling.

Summary:

When a bean node has an autowire byName attribute.

  1. All set method names in its class, such as setCat, will be searched to obtain a string with set removed and lowercase, that is, cat.

  2. Go to the spring container to find whether there is an object with this string name id.

  3. If any, take out the injection; If not, a null pointer exception is reported.

7.2.byType

byType

autowire byType

Using autowire byType first needs to ensure that objects of the same type are unique in the spring container. If it is not unique, a non unique exception will be reported.

NoUniqueBeanDefinitionException
  • 1

Test:

1. Modify the bean configuration of user: autowire = "byType"

2. Test, normal output

3. Register a cat bean object!

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>

<bean id="user" class="com.kuang.pojo.User" autowire="byType">
   <property name="str" value="qinjiang"/>
</bean>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4. Test, error: NoUniqueBeanDefinitionException

5. Delete cat2 and change the bean name of cat! Test! Because it is assembled by type, no exception will be reported and the final result will not be affected. Even removing the id attribute does not affect the result.

This is automatic assembly by type!

7.3. Use notes

Using annotations

jdk1.5 began to support annotations, and spring 2.5 began to fully support annotations.

Preparation: inject attributes by annotation.

1. Introduce the context file header into the spring configuration file

xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
  • 1
  • 2
  • 3
  • 4

2. Enable attribute annotation support!

<context:annotation-config/>
  • 1

@Autowired

  • @Autowired is automatically transferred by type and does not support id matching.
  • You need to import the package of spring AOP!

Test:

1. Remove the set method from the User class and use the @ Autowired annotation

public class User {
   @Autowired
   private Cat cat;
   @Autowired
   private Dog dog;
   private String str;

   public Cat getCat() {
       return cat;
  }
   public Dog getDog() {
       return dog;
  }
   public String getStr() {
       return str;
  }
}

2. The contents of the configuration file are displayed

<context:annotation-config/>

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat" class="com.kuang.pojo.Cat"/>
<bean id="user" class="com.kuang.pojo.User"/>
  • 1
  • 2
  • 3
  • 4
  • 5

3. Test, output results successfully!

[little crazy God science popularization time]

@Autowired(required=false) Description: false, the object can be null; true, the object must be saved and cannot be null.

//If the allowed object is null, set required = false, and the default is true
@Autowired(required = false)
private Cat cat;
  • 1
  • 2
  • 3

@Qualifier

  • @Autowired is automatically assembled according to the type. With @ Qualifier, it can be automatically assembled according to byName
  • @Qualifier cannot be used alone.

Test steps:

1. Modify the content of the configuration file to ensure that there are objects of type. And the name is not the default name of the class!

<bean id="dog1" class="com.kuang.pojo.Dog"/>
<bean id="dog2" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>
  • 1
  • 2
  • 3
  • 4

2. No Qualifier test was added and an error was reported directly

3. Add a Qualifier annotation to the attribute

@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Test, successful output!

@Resource

  • @If the Resource has a specified name attribute, first search the assembly by name according to the attribute;
  • Secondly, assemble in the default byName mode;
  • If none of the above is successful, it will be assembled automatically by byType.
  • If they are not successful, an exception is reported.

Entity class:

public class User {
   //If the allowed object is null, set required = false, and the default is true
   @Resource(name = "cat2")
   private Cat cat;
   @Resource
   private Dog dog;
   private String str;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

beans.xml

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
<bean id="cat2" class="com.kuang.pojo.Cat"/>

<bean id="user" class="com.kuang.pojo.User"/>
  • 1
  • 2
  • 3
  • 4
  • 5

Test result: OK

Configuration file 2: beans.xml, delete cat2

<bean id="dog" class="com.kuang.pojo.Dog"/>
<bean id="cat1" class="com.kuang.pojo.Cat"/>
  • 1
  • 2

Only annotations are retained on entity classes

@Resource
private Cat cat;
@Resource
private Dog dog;
  • 1
  • 2
  • 3
  • 4

Result: OK

Conclusion: byName search failed first; The byType search is successful.

Summary

@Similarities and differences between Autowired and @ Resource:

1. Both @ Autowired and @ Resource can be used to assemble bean s. Can be written on a field or on a setter method.

2. @ Autowired is assembled by type by default (belonging to the spring specification). By default, dependent objects must exist. If null value is allowed, its required property can be set to false, such as @ Autowired(required=false). If we want to use name assembly, it can be used in combination with @ Qualifier annotation

3. @ Resource (belonging to J2EE complex return), assembled by name by default, and the name can be specified through the name attribute. If the name attribute is not specified, when the annotation is written on the field, the default is to take the field name to search by name. If the annotation is written on the setter method, the default is to take the attribute name for assembly. Assemble by type when no bean matching the name is found. However, it should be noted that once the name attribute is specified, it will only be assembled by name.

They have the same function. They inject objects by annotation, but the execution order is different@ Autowired byType first, @ Resource byName first.

8. Development using annotations

explain

After spring 4, if you want to use annotation form, you must introduce aop package

In the configuration file, a context constraint must also be introduced

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

</beans>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

8.1. Implementation of bean

We used to use bean tags for bean injection, but in actual development, we usually use annotations!

1. Configure which packages to scan for annotations

<!--Specify annotation scan package-->
<context:component-scan base-package="com.kuang.pojo"/>
  • 1
  • 2

2. Write classes under the specified package and add annotations

@Component("user")
// Equivalent to < bean id = "user" class = "currently annotated class" / > in the configuration file
public class User {
   public String name = "Qin Jiang";
}
  • 1
  • 2
  • 3
  • 4
  • 5

3. Testing

@Test
public void test(){
   ApplicationContext applicationContext =
       new ClassPathXmlApplicationContext("beans.xml");
   User user = (User) applicationContext.getBean("user");
   System.out.println(user.name);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

8.2. Attribute injection

Using annotation injection properties

1. You can directly add @ value("value") to the direct name without providing a set method

@Component("user")
// Equivalent to < bean id = "user" class = "currently annotated class" / > in the configuration file
public class User {
   @Value("Qin Jiang")
   // Equivalent to < property name = "name" value = "Qin Jiang" / > in the configuration file
   public String name;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

2. If a set method is provided, @ value("value") is added to the set method;

@Component("user")
public class User {

   public String name;

   @Value("Qin Jiang")
   public void setName(String name) {
       this.name = name;
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

8.3. Derived notes

These annotations replace the configuration steps in the configuration file! More convenient and fast!

@Component three derived annotations

For better layering, Spring can use the other three annotations with the same functions. At present, which function is used is the same.

  • @Controller: controller layer
  • @Service: service layer
  • @Repository: dao layer

Writing these annotations is equivalent to giving this class to the Spring management assembly!

8.4. Automatic assembly notes

The automatic assembly of Bean has been talked about, which can be reviewed!

8.5. Scope

@scope

  • Singleton: by default, Spring creates this object in singleton mode. Close the factory and all objects will be destroyed.
  • prototype: multi instance mode. Close the factory and all objects will not be destroyed. The internal garbage collection mechanism will recycle
@Controller("user")
@Scope("prototype")
public class User {
   @Value("Qin Jiang")
   public String name;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

8.6. Summary

XML and annotation comparison

  • XML can be applied to any scenario, with clear structure and convenient maintenance
  • Annotations are not self provided classes and cannot be used. Development is simple and convenient

Integrated development of xml and annotation  : Recommend best practices

  • xml management Bean
  • Annotation complete attribute injection
  • In the process of use, there is no need to scan. The scanning is for the annotation on the class
<context:annotation-config/>  
  • 1

effect:

  • Make annotation driven registration to make annotations effective

  • It is used to activate the annotations on the bean s that have been registered in the spring container, that is, to register with spring

  • If you do not scan the package, you need to manually configure the bean

  • If it is driven without annotation, the injected value is null!

9. Configure based on Java classes

JavaConfig was originally a sub project of Spring. It provides Bean definition information through Java classes. In the version of Spring 4, JavaConfig has officially become the core function of Spring 4.

Test:

1. Write an entity class, Dog

@Component  //Mark this class as a component of Spring and put it in the container!
public class Dog {
   public String name = "dog";
}
  • 1
  • 2
  • 3
  • 4

2. Create a new config configuration package and write a MyConfig configuration class

@Configuration  //Represents that this is a configuration class
public class MyConfig {

   @Bean //Register a bean through the method. The return value here is the bean type, and the method name is the bean id!
   public Dog dog(){
       return new Dog();
  }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3. Testing

@Test
public void test2(){
   ApplicationContext applicationContext =
           new AnnotationConfigApplicationContext(MyConfig.class);
   Dog dog = (Dog) applicationContext.getBean("dog");
   System.out.println(dog.name);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

4. Output results successfully!

How do I import other configurations?

1. Let's write another configuration class!

@Configuration  //Represents that this is a configuration class
public class MyConfig2 {
}
  • 1
  • 2
  • 3

2. In the previous configuration class, we choose to import this configuration class

@Configuration
@Import(MyConfig2.class)  //Import and merge other configuration classes, similar to the inculde label in the configuration file
public class MyConfig {

   @Bean
   public Dog dog(){
       return new Dog();
  }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

We will see a lot about the configuration of this Java class in SpringBoot and SpringCloud later. We need to know the role of these annotations!

10. Agency mode

Why learn the agent mode? Because the underlying mechanism of AOP is dynamic agent!

Proxy mode:

  • Static proxy
  • Dynamic agent

Before learning aop, we should first understand the agent mode!

10.1 static agent

Static agent role analysis

  • Abstract role: generally implemented using interfaces or abstract classes

  • Real role: the role represented

  • Agent role: agent real role; After representing a real role, you usually do some ancillary operations

  • Customer: use the agent role to perform some operations

code implementation

Rent. Java is an abstract role

//Abstract role: rent a house
public interface Rent {
   public void rent();
}
  • 1
  • 2
  • 3
  • 4

Host. Java is the real role

//Real role: landlord, the landlord wants to rent the house
public class Host implements Rent{
   public void rent() {
       System.out.println("House rental");
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

Proxy. Java is the proxy role

//Agent role: Intermediary
public class Proxy implements Rent {

   private Host host;
   public Proxy() { }
   public Proxy(Host host) {
       this.host = host;
  }

   //Rent a house
   public void rent(){
       seeHouse();
       host.rent();
       fare();
  }
   //House viewing
   public void seeHouse(){
       System.out.println("Show the tenant");
  }
   //Intermediary fee
   public void fare(){
       System.out.println("Intermediary fee");
  }
}

Client. Java is the client

//Customers, general customers will find agents!
public class Client {
   public static void main(String[] args) {
       //The landlord wants to rent a house
       Host host = new Host();
       //The intermediary helps the landlord
       Proxy proxy = new Proxy(host);

       //You go to the agency!
       proxy.rent();
  }
}

Analysis: in this process, you are in direct contact with an intermediary, just like in real life. You can't see the landlord, but you still rent the landlord's house through an agent. This is the so-called agent model. The program comes from life, so people who learn programming can generally look at what happens in life more abstractly.

Benefits of static agents:

  • Can make our real role more pure. No longer pay attention to some public things
  • The public business is completed by the agent, which realizes the division of business,
  • When the public business expands, it becomes more centralized and convenient

Disadvantages:

  • With more classes and more proxy classes, the workload becomes larger and the development efficiency decreases

We want the benefits of static agent, but we don't want the disadvantages of static agent, so we have dynamic agent!

10.2. Static agent re understanding

After the students' practice, let's give another example to consolidate everyone's learning!

Exercise steps:

1. Create an abstract role, such as the user business we usually do, which is abstracted to add, delete, modify and check!

//Abstract role: add, delete, modify and query business
public interface UserService {
   void add();
   void delete();
   void update();
   void query();
}

2. We need a real object to complete these operations

//Real object, the person who completes the operation of addition, deletion, modification and query
public class UserServiceImpl implements UserService {

   public void add() {
       System.out.println("Added a user");
  }

   public void delete() {
       System.out.println("A user was deleted");
  }

   public void update() {
       System.out.println("A user has been updated");
  }

   public void query() {
       System.out.println("A user was queried");
  }
}

3. The demand is coming. Now we need to add a log function. How to implement it!

  • Idea 1: add code on the implementation class [trouble!]
  • Idea 2: using an agent to do this, you can realize this function without changing the original business!

4. Set up a proxy class to handle logs! delegable role

//Agent role, in which the implementation of log is added
public class UserServiceProxy implements UserService {
   private UserServiceImpl userService;

   public void setUserService(UserServiceImpl userService) {
       this.userService = userService;
  }

   public void add() {
       log("add");
       userService.add();
  }

   public void delete() {
       log("delete");
       userService.delete();
  }

   public void update() {
       log("update");
       userService.update();
  }

   public void query() {
       log("query");
       userService.query();
  }

   public void log(String msg){
       System.out.println("Yes"+msg+"method");
  }

}

5. Test access class:

public class Client {
   public static void main(String[] args) {
       //Real business
       UserServiceImpl userService = new UserServiceImpl();
       //proxy class
       UserServiceProxy proxy = new UserServiceProxy();
       //Use the agent class to realize the log function!
       proxy.setUserService(userService);

       proxy.add();
  }
}

OK, now there should be no problem with the agent mode. The key point is that you need to understand the idea;

We have enhanced the original functions without changing the original code, which is the core idea of AOP

AOP: vertical development, horizontal development

10.3 dynamic agent

  • The role of dynamic agent is the same as that of static agent

  • The proxy class of dynamic proxy is dynamically generated. The proxy class of static proxy is written in advance

  • Dynamic agents are divided into two categories: one is interface based dynamic agents, and the other is class based dynamic agents

    • Dynamic agent based on interface -- JDK dynamic agent
    • Class based dynamic proxy – cglib
    • Now javasist is used to generate dynamic agents
    • We use the native code of JDK to implement it here. The rest are the same

The dynamic proxy of JDK needs to know two classes

Core: InvocationHandler and Proxy. Open the JDK help document and have a look

[InvocationHandler: call handler]

Object invoke(Object proxy, method method, Object[] args);
//parameter
//Proxy - the proxy instance that calls the method
//Method - the method corresponds to the instance that invokes the interface method on the proxy instance. The declared class of the method object will be the interface declared by the method, which can be the super interface of the proxy interface of the proxy class inheriting the method.
//args - array of objects containing method calls that pass the parameter values of the proxy instance, or null if the interface method has no parameters. The parameters of the primitive type are contained in an instance of the appropriate primitive wrapper class, such as java.lang.Integer or java.lang.Boolean.

[Proxy: Proxy]

//Generate proxy class
public Object getProxy(){
   return Proxy.newProxyInstance(this.getClass().getClassLoader(),
                                 rent.getClass().getInterfaces(),this);
}

code implementation

Abstract characters and real characters are the same as before!

Rent. Java is an abstract role

//Abstract role: rent a house
public interface Rent {
   public void rent();
}

Host. Java is the real role

//Real role: landlord, the landlord wants to rent the house
public class Host implements Rent{
   public void rent() {
       System.out.println("House rental");
  }
}

ProxyInvocationHandler. java is the proxy role

public class ProxyInvocationHandler implements InvocationHandler {
   private Rent rent;

   public void setRent(Rent rent) {
       this.rent = rent;
  }

   //Generate an agent class, focusing on the second parameter to obtain the abstract role to be represented! It used to be a role, but now it can represent a kind of role
   public Object getProxy(){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(),
               rent.getClass().getInterfaces(),this);
  }

   // Proxy: proxy class method: the method object of the calling handler of the proxy class
   // Process method calls on proxy instances and return results
   @Override
   public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {
       seeHouse();
       //Core: essence is realized by reflection!
       Object result = method.invoke(rent, args);
       fare();
       return result;
  }

   //House viewing
   public void seeHouse(){
       System.out.println("Show the tenant");
  }
   //Intermediary fee
   public void fare(){
       System.out.println("Intermediary fee");
  }

}

Client . java

//tenant
public class Client {

   public static void main(String[] args) {
       //Real role
       Host host = new Host();
       //Call handler for proxy instance
       ProxyInvocationHandler pih = new ProxyInvocationHandler();
       pih.setRent(host); //Put the real character in!
       Rent proxy = (Rent)pih.getProxy(); //Dynamically generate the corresponding proxy class!
       proxy.rent();
  }

}

Core: a dynamic agent generally represents a certain type of business. A dynamic agent can represent multiple classes, and the agent is the interface

10.4 deepening understanding

Let's use dynamic proxy to implement UserService written later!

We can also write a general dynamic proxy implementation class! All proxy objects can be set to Object!

public class ProxyInvocationHandler implements InvocationHandler {
   private Object target;

   public void setTarget(Object target) {
       this.target = target;
  }

   //Generate proxy class
   public Object getProxy(){
       return Proxy.newProxyInstance(this.getClass().getClassLoader(),
               target.getClass().getInterfaces(),this);
  }

   // Proxy: proxy class
   // Method: the method object of the calling handler of the proxy class
   public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {
       log(method.getName());
       Object result = method.invoke(target, args);
       return result;
  }

   public void log(String methodName){
       System.out.println("Yes"+methodName+"method");
  }

}

Test!

public class Test {
   public static void main(String[] args) {
       //Real object
       UserServiceImpl userService = new UserServiceImpl();
       //Call handler for proxy object
       ProxyInvocationHandler pih = new ProxyInvocationHandler();
       pih.setTarget(userService); //Sets the object to proxy
       UserService proxy = (UserService)pih.getProxy(); //Dynamically generate proxy class!
       proxy.delete();
  }
}

Test, add, delete, modify and check the results!

10.5 benefits of dynamic agents

It has all the static agents. It also has all the static agents that don't have!

  • Can make our real role more pure. No longer pay attention to some public things
  • The public business is completed by the agent, which realizes the division of business,
  • When the public business expands, it becomes more centralized and convenient
  • A dynamic agent, generally acting for a certain kind of business
  • A dynamic proxy can proxy multiple classes, and the proxy is the interface!

11.AOP

11.1. What is AOP

AOP (Aspect Oriented Programming) means: Aspect Oriented Programming, which realizes the unified maintenance of program functions through precompiled mode and runtime dynamic agent. AOP is the continuation of OOP, a hot spot in software development, an important content in Spring framework, and a derivative paradigm of functional programming. AOP can isolate each part of business logic, reduce the coupling between each part of business logic, improve the reusability of program, and improve the efficiency of development.

11.2. The role of AOP in Spring

Provide declarative transactions; Allows you to customize the cut plane

The following nouns need to be understood:

  • Crosscutting concerns: methods or functions that span multiple modules of an application. That is, the part that has nothing to do with our business logic, but we need to focus on is crosscutting concerns. Such as log, security, cache, transaction and so on
  • ASPECT: a special object whose crosscutting concerns are modularized. That is, it is a class.
  • Advice: work that must be completed in all aspects. That is, it is a method in a class.
  • Target: the notified object.
  • Proxy: an object created after notification is applied to the target object.
  • PointCut: the definition of the "place" where the aspect notification is executed.
  • Join point: the execution point that matches the pointcut.

In spring AOP, crosscutting logic is defined through Advice. Spring supports five types of Advice:

That is, Aop adds new functions without changing the original code

11.3. Using Spring to implement Aop

[key] to use AOP weaving, you need to import a dependency package!

<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
   <groupId>org.aspectj</groupId>
   <artifactId>aspectjweaver</artifactId>
   <version>1.9.4</version>
</dependency>

11.3.1. Implementation through Spring API

The first way

First, write our business interface and implementation class

public interface UserService {

   public void add();

   public void delete();

   public void update();

   public void search();

}
public class UserServiceImpl implements UserService{

   @Override
   public void add() {
       System.out.println("Add user");
  }

   @Override
   public void delete() {
       System.out.println("delete user");
  }

   @Override
   public void update() {
       System.out.println("Update user");
  }

   @Override
   public void search() {
       System.out.println("Query user");
  }
}

Then write our enhancement class. We write two, one pre enhancement and one post enhancement

public class Log implements MethodBeforeAdvice {

   //Method: the method of the target object to execute
   //objects: parameters of the called method
   //Object: target object
   @Override
   public void before(Method method, Object[] objects, Object o) throws Throwable {
       System.out.println( o.getClass().getName() + "of" + method.getName() + "Method was executed");
  }
}
public class AfterLog implements AfterReturningAdvice {
   //returnValue return value
   //Method called method
   //args parameter of the object of the called method
   //Target the called target object
   @Override
   public void afterReturning(Object returnValue, Method method, Object[] args,Object target) throws Throwable {
       System.out.println("Yes" + target.getClass().getName()
       +"of"+method.getName()+"method,"
       +"Return value:"+returnValue);
  }
}

Finally, register in the spring file and implement aop cut in implementation. Pay attention to import constraints

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
      xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:aop="http://www.springframework.org/schema/aop"
      xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

   <!--register bean-->
   <bean id="userService" class="com.kuang.service.UserServiceImpl"/>
   <bean id="log" class="com.kuang.log.Log"/>
   <bean id="afterLog" class="com.kuang.log.AfterLog"/>

   <!--aop Configuration of-->
   <aop:config>
       <!--breakthrough point expression:The expression matches the method to execute-->
       <aop:pointcut id="pointcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
       <!--Perform wrap; advice-ref Execution method . pointcut-ref breakthrough point-->
       <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
       <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
   </aop:config>

</beans>

test

public class MyTest {
   @Test
   public void test(){
       ApplicationContext context = newClassPathXmlApplicationContext("beans.xml");
       UserService userService = (UserService) context.getBean("userService");
       userService.search();
  }
}

The importance of Aop: very important. We must understand the ideas, mainly the understanding of ideas

Spring's Aop combines public business (log, security, etc.) with domain business. When executing domain business, public business will be added to realize the reuse of public business. Domain business is more pure, and programs focus on domain business. Its essence is still dynamic agent

11.3.2. Implement Aop with user-defined classes

The second way

The target business class remains the same as userServiceImpl

Step 1: write our own cut in class

public class DiyPointcut {

   public void before(){
       System.out.println("---------Before method execution---------");
  }
   public void after(){
       System.out.println("---------After method execution---------");
  }
   
}

To configure in spring

<!--The second way is to customize the implementation-->
<!--register bean-->
<bean id="diy" class="com.kuang.config.DiyPointcut"/>

<!--aop Configuration of-->
<aop:config>
   <!--The second way: use AOP Label Implementation of-->
   <aop:aspect ref="diy">
       <aop:pointcut id="diyPonitcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
       <aop:before pointcut-ref="diyPonitcut" method="before"/>
       <aop:after pointcut-ref="diyPonitcut" method="after"/>
   </aop:aspect>
</aop:config>

Test:

public class MyTest {
   @Test
   public void test(){
       ApplicationContext context = newClassPathXmlApplicationContext("beans.xml");
       UserService userService = (UserService) context.getBean("userService");
       userService.add();
  }
}

11.3.4. Implementation using annotations

The third way

Step 1: write an enhanced class for annotation implementation

package com.kuang.config;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

@Aspect
public class AnnotationPointcut {
   @Before("execution(* com.kuang.service.UserServiceImpl.*(..))")
   public void before(){
       System.out.println("---------Before method execution---------");
  }

   @After("execution(* com.kuang.service.UserServiceImpl.*(..))")
   public void after(){
       System.out.println("---------After method execution---------");
  }

   @Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
   public void around(ProceedingJoinPoint jp) throws Throwable {
       System.out.println("Surround front");
       System.out.println("autograph:"+jp.getSignature());
       //Execute target method
       Object proceed = jp.proceed();
       System.out.println("After surround");
       System.out.println(proceed);
  }
}

Step 2: register the bean in the Spring configuration file and add the configuration supporting annotation

<!--The third way:Annotation implementation-->
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<aop:aspectj-autoproxy/>

AOP: AspectJ AutoProxy: description

adopt aop Namespace<aop:aspectj-autoproxy />Declaration is automatically spring Which configurations are in the container@aspectJ Tangential bean Create a proxy and weave in the cut. of course, spring It is still used internally AnnotationAwareAspectJAutoProxyCreator The creation of automatic agent has been carried out, but the details of the specific implementation have been<aop:aspectj-autoproxy />It's hidden

<aop:aspectj-autoproxy />There is one proxy-target-class Property, default to false,Indicates use jdk Dynamic proxy weaving enhancement when configured as<aop:aspectj-autoproxy  poxy-target-class="true"/>When, it means to use CGLib Dynamic agent technology weaving enhancement. But even if proxy-target-class Set to false,If the target class does not declare an interface, then spring Will be used automatically CGLib Dynamic proxy.

Topics: Spring mvc