Spring framework xml-based configuration

Preface

I just finished learning the ssm framework, and review the configuration of the spring framework based on xm and annotation l. If there is something wrong, please leave a message below. I hope to consolidate my understanding of the framework and help everyone, thank you!

Two core ideas of spring framework

IOC Inversion of Control

IOC stands for (Inversion of Control), which is inversion of control. Using my own understanding (haha) is to give the right to create objects to Spring's IOC container, and let the IOC container implement the instantiation of objects, which has the effect of reducing the coupling between programs. When it comes to IOC, there is a concept, dependency injection, which will be explained later!

AOP aspect-oriented programming

AOP, namely (Aspect Oriented Programming), aspect-oriented programming. Suppose there is a scenario: when you write a small project yourself, at this time you find that dozens of methods to operate on the database do not have transaction control. Now that’s fine, you have to try/try each method one by one. catch/finally, then you will be uncomfortable. The idea of ​​AOP solves this coupling well.

XML-based IOC configuration process (IDEA)

First create a maven project and then configure dependency in the pom.xml file

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
    </dependencies>

Affirm that if the introduction of coordinates is slow, it can be changed to Alibaba Cloud's mirror image, the method can be Baidu, there are many tutorials!
Then create a new entity class

/**用户信息实体类
 * @author Cocowwy
 * @create 2020-04-04-23:56
 */
public class User {
    private String name;
    private Integer age;
    
    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
}

Then write the configuration file under the main/resources directory. First write this block

<?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">
</beans>

Because we just wrote an entity class, since we want to use IOC to create an instance, then configure

 <bean id="user" class="cn.hncu.domain.User"></bean>

The id is named by yourself, but if you want to create an instance object in the code, you need this id as a unique identifier. The class attribute is the fully qualified class name of the class.

With the class and the configuration file, how do you get the instance object by reading the configuration file in the code? ?
In the JAVA code:

/**
 * @author Cocowwy
 * @create 2020-04-04-0:09
 */
public class test {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //返回结果是obj类型,记得强转!
        System.out.println(ac.getBean("user"));//控制台输出:cn.hncu.domain.User@3ffc5af1
    }
}

Print out the address to show that the object is created successfully, this is the inversion of control, and transfer the control power of the new object to the spring container

So how do you assign a value to an object?

Method 1: Through the construction method
    <bean id="user" class="cn.hncu.domain.User">
        <constructor-arg index="0" value="王小胖"/>
        <constructor-arg index="1" value="20"/>
    </bean>

When we add a constructor method to the entity class (alt+ins generates a constructor), idea will prompt that the configuration file needs a new label constructor-arg. The label index indicates the number of parameters. Note that the subscript starts from 0, value Value is the value that needs to be assigned.
Next, rewrite the tosSring() method in the entity class to see the result!

//构造函数
    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
//重写toString
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

test:

/**
 * @author Cocowwy
 * @create 2020-04-04-0:09
 */
public class test {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //返回结果是obj类型,记得强转!
        System.out.println(ac.getBean("user"));//控制台输出:User{name='王小胖', age=20}
    }
}

You can see that the assignment was successful!

Method 2: Through attribute injection (more commonly used)

First delete the constructor of the previous method and configure
as follows

    <bean id="user" class="cn.hncu.domain.User">
        <property name="name" value="王大胖"></property>
        <property name="age" value="21"></property>
    </bean>

The name attribute of the property tag refers to the attribute name of the entity class, and the value is the assigned value.
test:

/**
 * @author Cocowwy
 * @create 2020-04-04-0:09
 */
public class test {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //返回结果是obj类型,记得强转!
        System.out.println(ac.getBean("user"));//控制台输出:User{name='王大胖', age=21}
    }
}
Now that we know the injection of basic tree properties, let’s talk about special properties, such as collections, maps, arrays, etc. How do we assign values ​​to properties?
First is the List collection

First modify the entity class and inject it through the getset method

/**
 * 用户信息实体类
 *
 * @author Cocowwy
 * @create 2020-04-04-23:56
 */
public class User {
    private String name;
    private Integer age;
    private List<String> frinds;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", frinds=" + frinds +
                '}';
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public List<String> getFrinds() {
        return frinds;
    }

    public void setFrinds(List<String> frinds) {
        this.frinds = frinds;
    }
}

Then bean.xml configuration is as follows:

    <bean id="user" class="cn.hncu.domain.User">
        <property name="name" value="王小胖"></property>
        <property name="age" value="20"></property>
        <property name="frinds" >
            <array>
                <value>王一胖</value>
                <value>王二胖</value>
                <value>王三胖</value>
            </array>
        </property>
    </bean>

You can see that the name value of the property tag is the name of the List, and the property contains the arry tag. Each value corresponds to each value in the set. The
results are as follows:

/**
 * @author Cocowwy
 * @create 2020-04-04-0:09
 */
public class test {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //返回结果是obj类型,记得强转!
        System.out.println(ac.getBean("user"));//User{name='王小胖', age=20, frinds=[王一胖, 王二胖, 王三胖]}

    }
}

Array and List steps are the same, so we won’t demonstrate it!

Next is the Map collection

Add attributes and geiset methods to entities, rewrite toString

package cn.hncu.domain;

import java.util.List;
import java.util.Map;

/**
 * 用户信息实体类
 *
 * @author Cocowwy
 * @create 2020-04-04-23:56
 */
public class User {
    private String name;
    private Integer age;
    private List<String> frinds;
    private Map<String,String> thingColor;

    public Map<String, String> getThingColor() {
        return thingColor;
    }
    
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", frinds=" + frinds +
                ", thingColor=" + thingColor +
                '}';
    }

    public void setThingColor(Map<String, String> thingColor) {
        this.thingColor = thingColor;
    }


    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public List<String> getFrinds() {
        return frinds;
    }

    public void setFrinds(List<String> frinds) {
        this.frinds = frinds;
    }
}

Then bean.xml configuration is as follows

    <bean id="user" class="cn.hncu.domain.User">
        <property name="name" value="王小胖"></property>
        <property name="age" value="20"></property>
        <property name="frinds" >
            <array>
                <value>王一胖</value>
                <value>王二胖</value>
                <value>王三胖</value>
            </array>
        </property>
        <property name="thingColor">
            <map>
                <entry key="上衣" value="红色"></entry>
                <entry key="裤子" value="蓝色"></entry>
                <entry key="头发" value="黑色"></entry>
            </map>
        </property>
    </bean>

You can see that the property tag whose name is the map collection wraps the map tag. There is an entry tag in the map, which represents a key-value pair, which is easy to understand!
test:

package cn.hncu;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author Cocowwy
 * @create 2020-04-04-0:09
 */
public class test {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //返回结果是obj类型,记得强转!
        System.out.println(ac.getBean("user"));//User{name='王小胖', age=20, frinds=[王一胖, 王二胖, 王三胖], thingColor={上衣=红色, 裤子=蓝色, 头发=黑色}}

    }
}

properties?

The same add getset method and rewrite toString

 private Properties properties;

bean.xml new configuration

        <property name="properties">
            <props>
                <prop key="体重">140</prop>
            </props>
        </property>

test:

package cn.hncu;

import cn.hncu.domain.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author Cocowwy
 * @create 2020-04-04-0:09
 */
public class test {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //返回结果是obj类型,记得强转!
        System.out.println(ac.getBean("user"));
       // User {name='王小胖', age=20, frinds=[王一胖, 王二胖, 王三胖], thingColor={上衣=红色, 裤子=蓝色, 头发=黑色}, properties={体重=140}}
    }
}

What about other reference types needed in the collection? ? ?

First create two entities, you can see that the generic type of the List collection is Account

package cn.hncu.domain;

import java.util.List;
import java.util.Map;
import java.util.Properties;

/**
 * 用户信息实体类
 *
 * @author Cocowwy
 * @create 2020-04-04-23:56
 */
public class User {
    private String name;
    private Integer age;
    private List<Account> accounts;

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", accounts=" + accounts +
                '}';
    }

    public String getName() {
        return name;
    }

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

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public List<Account> getAccounts() {
        return accounts;
    }

    public void setAccounts(List<Account> accounts) {
        this.accounts = accounts;
    }
}

Account entity

package cn.hncu.domain;

/**
 * @author Cocowwy
 * @create 2020-04-04-11:32
 */
public class Account {
    private String username;
    private String money;

    @Override
    public String toString() {
        return "Account{" +
                "username='" + username + '\'' +
                ", money='" + money + '\'' +
                '}';
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getMoney() {
        return money;
    }

    public void setMoney(String money) {
        this.money = money;
    }
}


How to configure it next? This is a clear understanding of this place, whether it is a good Map or an array, any place needs to introduce entities to do so!
The bean.xml configuration is as follows:

    <bean id="account" class="cn.hncu.domain.Account">
        <property name="username" value="王小胖工行卡"></property>
        <property name="money" value="300000"></property>
    </bean>

    <bean id="user" class="cn.hncu.domain.User">
        <property name="name" value="王小胖"></property>
        <property name="age" value="20"></property>
        <property name="accounts">
            <list>
                <ref bean="account"></ref>
            </list>
        </property>
    </bean>

First of all, because we have created a new entity, we naturally need to inject it into the IOC container, so configure it first, and then we can see that the property in the bean has a ref attribute? That's it, the bean referenced by ref is the bean with id=account that we just injected into the IOC container, and ref is found by id. By analogy, it is not difficult to conclude that we refer to the bean in the IOC container by replacing the value attribute with the ref attribute.
test:


/**
 * @author Cocowwy
 * @create 2020-04-04-0:09
 */
public class test {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //返回结果是obj类型,记得强转!
        System.out.println(ac.getBean("user"));
      //User{name='王小胖', age=20, accounts=[Account{username='王小胖工行卡', money='300000'}]}
    }
}

The above is the way to assign values ​​to entities, that is, our DI, dependency injection. This is Spring's XML-based IOC configuration. It's relatively rough, but it's relatively simple configuration!

XML-based AOP configuration process (IDEA)

XML-based AOP configuration in spring
1. Give the notification bean to spring to manage
2. Use the aop:config tag to indicate the start of AOP configuration
3. Use the aop: aspect tag to indicate the start of configuring the aspect
id attribute: provide a unique flag
ref for the aspect Attribute: the id of the bean specifying the notification class
4. Use the corresponding tag inside the aop:aspect tag to configure the type of notification.
Our current example will make the pringLog method execute before the pointcut method is executed, so pre-notify
aop:before : Indicates the configuration of the pre-notification
method attribute: used to specify which method in the Logger class, the pre-notification
pointcut attribute: used to specify the entry point expression, the meaning of the expression refers to which methods in the business layer enhance the
entry point expression Type writing:
Keyword: execution (expression)
expression:
access modifier return value Package name. Package name. Package name...Class name. Method name (parameter list)
Standard writing: public void com.hncu.service.impl The .AccountServiceAOP.saveAccount()
access modifier can be omitted: void com.hncu.service.impl.AccountServiceAOP.saveAccount() The
return value can use wildcards: indicates any return value: * com.hncu.service.impl.AccountServiceAOP.saveAccount( )
Package name can use wildcards denote any package represents any package, but there are a few levels pack, you need to write a few *:. * . . . ... AccountServiceAOP.saveAccount ()
package name also can be used ... indicates that the current package and its subpackages :* …AccountServiceAOP.saveAccount()
Both class name and method name can be used
to realize wildcarding: * . ()
Parameter list:
You can write data
type directly. Basic type write name directly
. Write package name. Class name method. Java .lang.String
can use wildcards to represent any type, but it must have parameters. It
can be used... to indicate whether there are parameters or not, and any type can be made with parameters.
Full configuration:
. (…)
The usual entry point expression in actual development Writing
method All methods under the implementation class of the cutter business layer
* com.hncu.service.impl.
.*(…)

rely:

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.8.7</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-tx</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>

    </dependencies>

AOP aspect configuration

!--    配置AOP-->
    <aop:config>
        <!--配置切入点表达式  id:用于指定表达式的唯一表示  expression:用于指定表达式内容
            此标签卸写在aop:aspect标签内部只能当前切面使用。
           它还可以写在aop:aspect外面(标签必须在切面你之前!!!!!!)-->
        <aop:pointcut id="pt1" expression="execution(* com.hncu.service.impl.*.*(..))"/>
        <!--配置切面-->
        <aop:aspect id="logAdvice" ref="logger">
<!--            配置通知的类型,并且建立通知方法和切入点方法的关联-->
<!--            前置通知,在切入点执行方法之前执行-->
                        <aop:before method="beforeprintLog" pointcut-ref="pt1"></aop:before>
<!--            后置通知,在切入点方法正常执行之后执行,它和异常通知永远只能执行一个-->
                        <aop:after-returning method="afterReturnprintLog" pointcut-ref="pt1"></aop:after-returning>
<!--            异常通知,在切入点方法执行异常之后执行,它和后置通知永远只能执行一个-->
                        <aop:after-throwing method="afterThrowingprintLog" pointcut-ref="pt1"></aop:after-throwing>
<!--            最终通知,无论切入点方法是否正常执行它都会在其后面执行-->
                        <aop:after method="afterprintLog" pointcut-ref="pt1"></aop:after>
<!--            配置环绕通知  详细的注释请看Logger类中-->
                        <aop:around method="arroundPrintLog" pointcut-ref="pt1"></aop:around>
        </aop:aspect>
    </aop:config>

Logger class.

package com.hncu.utils;

import org.aspectj.lang.ProceedingJoinPoint;

/**
 * @author Cocowwy
 * @create 2020-04-04-11:23
 * 用于记录日志的工具类,它里面提供了公共代码
 */
public class Logger {
    /**
     * 用于打印日志,计划让其在切入点方法执行之前执行(切入点方法就是业务层方法)
     * 前置通知
     */
    public void beforeprintLog() {
        System.out.println("前置通知Logger类中的beforeprintLog方法开始记录日志了。。。");
    }

    /**
     * 后置通知
     */
    public void afterReturnprintLog() {
        System.out.println("后置通知Logger类中的afterReturnprintLog方法开始记录日志了。。。");
    }

    /**
     * 异常通知
     */
    public void afterThrowingprintLog() {
        System.out.println("异常通知Logger类中afterThrowingprintLog方法开始记录日志了。。。");
    }

    /**
     * 最终通知
     */
    public void afterprintLog() {
        System.out.println("最终通知Logger类中的afterprintLog方法开始记录日志了。。。");
    }

    /**
     * 环绕通知
     * 问题:当我们配置了环绕通知之后,切入点方法没有执行,通知方法执行了
     * 分析:通过对比动态代理中的环绕通知代码,发现动态代理中环绕通知有明确的切入点方法调用
     * 而我们的代码中没有,
     * 解决:spring框架为我们提供了一个接口:ProceedingJoinPoint该接口有一个方法proceed(),
     * 此方法就相当于明确调用切入点方法
     * 该接口可以作为环绕通知的方法参数,在程序执行时spring框架会为我们提供该接口的实现类供我们使用
     * <p>
     * spring中的环绕通知:
     * 它是spring框架为我们提供的一种可以在代码中手动控制增强方式何时执行的方式
     */
    public Object arroundPrintLog(ProceedingJoinPoint pjp) {
        Object rtvalue = null;
        try {
            Object[] args = pjp.getArgs();//得到方法执行所需的参数
            System.out.println("环绕前置通知");
            rtvalue = pjp.proceed(args);//明确调用业务层方法(切入点方法)
            System.out.println("环绕后置通知");
            return rtvalue;
        } catch (Throwable throwable) {
            System.out.println("环绕异常通知");
            throw new RuntimeException(throwable);
        } finally {
            System.out.println("环绕最终通知");
        }
    }
}

The above is the XML-based configuration, and spring annotation-based configuration will be done later!

Guess you like

Origin blog.csdn.net/Pzzzz_wwy/article/details/105443258