This is the sixth day of my participation in the August More text Challenge. For details, see:August is more challenging

The introduction

I wrote a quick introduction to Spring earlier to help you get up and running quickly. Since this is a quick start, I will certainly explain some general knowledge, so for some in-depth content of Spring, I decided to divide it into two parts, hope to help you.

The scope of the Bean

I’m sure you know the scope, so let’s take a look at an example. Create a bean class:

package com.itcast.spring.bean.scope;

public class Car {

	private String brand;
	private String corp;
	private double price;
	private int maxSpeed;

	public String getBrand(a) {
		return brand;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}

	public String getCorp(a) {
		return corp;
	}

	public void setCorp(String corp) {
		this.corp = corp;
	}

	public double getPrice(a) {
		return price;
	}

	public void setPrice(double price) {
		this.price = price;
	}

	public int getMaxSpeed(a) {
		return maxSpeed;
	}

	public void setMaxSpeed(int maxSpeed) {
		this.maxSpeed = maxSpeed;
	}

	@Override
	public String toString(a) {
		return "Car [brand=" + brand + ", corp=" + corp + ", price=" + price + ", maxSpeed=" + maxSpeed + "]"; }}Copy the code

In the configuration file:


      
<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="car" class="com.itcast.spring.bean.scope.Car">
		<property name="brand" value="BMW"></property>
		<property name="corp" value="ShangHai"></property>
		<property name="price" value="350000"></property>
		<property name="maxSpeed" value="240"></property>
	</bean>

</beans>
Copy the code

Next, write the test code:

public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-scope.xml");
		Car car = (Car) ctx.getBean("car");
		Car car2 = (Car) ctx.getBean("car");
		System.out.println(car == car2);
}
Copy the code

Running result:

true
Copy the code

From this we know that the two cars that were taken out of the container are actually the same object. Why is that? By default, Spring sets a “singleton” for a bean. In this case, the bean is a “singleton”, meaning that there is only one instance of the bean in the entire container. We can set the scope of a bean by using the Scope property in the bean node.


      
<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="car" class="com.itcast.spring.bean.scope.Car" scope="prototype">
		<property name="brand" value="BMW"></property>
		<property name="corp" value="ShangHai"></property>
		<property name="price" value="350000"></property>
		<property name="maxSpeed" value="240"></property>
	</bean>

</beans>
Copy the code

Here I’ve set the scope of the bean to prototype, which means prototype. In this case, every time I get the bean from the container, it returns a new object. We rerun the test code and find that the result is false, confirming the conclusion.

Use external properties files

When configuring beans in configuration files, it is sometimes necessary to mix system deployment details into the bean configuration, and these deployment details actually need to be separated from the bean. Demand for such, Spring provides an accomplished the BeanFactory post processor, part of the processor allows the user to configure a bean migrated to properties files, Can be used in bean configuration file form ${var} variable, accomplished loading the properties in the properties file, and use these attributes to substitution variables. Let’s say I need to configure basic database connection information in the Spring configuration file. We should extract this basic information into a properties file (db_info.properties) and put it outside:

user=root
password=123456
url=jdbc:mysql:///test
driver=com.mysql.jdbc.Driver
Copy the code

Then configure c3P0’s bean class:


      
<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-4.0.xsd">

	<! -- Import properties file -->
	<context:property-placeholder location="classpath:db_info.properties"/>
	
	<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
		<property name="user" value="${user}"></property>
		<property name="password" value="${password}"></property>
		<property name="driverClass" value="${driver}"></property>
		<property name="jdbcUrl" value="${url}"></property>
	</bean>

</beans>
Copy the code

Write test code:

public static void main(String[] args) throws SQLException {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-properties.xml");
		ComboPooledDataSource dataSource = (ComboPooledDataSource) ctx.getBean("dataSource"); System.out.println(dataSource.getConnection()); }}Copy the code

Running result:

com.mchange.v2.c3p0.impl.NewProxyConnection@35a50a4c
Copy the code

The database connection will also be obtained successfully, and the subsequent modification process will be very convenient, simply by looking for the properties file to connect to the database.

SpEL

SpEL is the Spring Expression Language, an expression language that supports querying and manipulating object graphs. Its syntax is similar to EL in JSP, but it is delimited by #{}, and all characters inside curly braces are considered SpEL. 1. Literal

But if you use SpEL only for assignment of literal values, it’s unnecessary. Therefore, it is generally not used for assigning literal values. 2. Reference beans and their properties and methods

  • Reference to other objects

<property name=”prefix” value=”#{prefixGenerator}”></property>

  • References to other object properties

<property name=”suffix” value=”#{sequenceGenerator2.suffix}”></property>

  • References to other object methods

<property name=”suffix” value=”#{sequenceGenerator2.toString}”></property>

  • A static property that refers to another object

<property name=”initValue” value=”#{T(java.lang.Math).PI}”></property>

SpEL also supports operators such as +, -, *, /, and %. Supports logical operators such as and, OR, NOT, if-else, etc. Supports regular expressions.

The life cycle of the Bean

The SpringIOC container can manage the bean lifecycle, and Spring allows specified tasks to be performed at specific points in the bean lifecycle. The SpringIOC container manages the bean lifecycle as follows:

  1. Bean instances are created through a constructor or factory method
  2. Sets values for the bean’s properties and references to other beans
  3. Call the bean’s initialization method
  4. The bean is ready to use
  5. The bean’s destruction method is called when the container is closed

Many people may wonder why a normal bean class has initialization and destruction methods. Of course there isn’t, but Spring provides a way to specify the bean’s initialization and destruction methods. Let’s write a case to get a feel for it. Create a bean class:

package com.itcast.spring.bean.cycle;

public class Car {

	private String brand;

	public Car(a) {
		System.out.println("Constructor...");
	}

	public void setBrand(String brand) {
		System.out.println("setBrand...");
		this.brand = brand;
	}

	public void init(a) {
		System.out.println("init...");
	}

	public void destory(a) {
		System.out.println("destory..."); }}Copy the code

In the configuration file:


      
<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="car" class="com.itcast.spring.bean.cycle.Car"
		init-method="init" destroy-method="destory">
		<property name="brand" value="BMW"></property>
	</bean>

</beans>
Copy the code

Write test code:

public static void main(String[] args) {
		ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("beans-cycle.xml");
		Car car = (Car) ctx.getBean("car");
		System.out.println(car);
		
		// Close the IOC container
		ctx.close();
	}
Copy the code

Running result:

Constructor... setBrand... init... Com. Itcast. Spring. Beans. Cycle. Car @ 91161 c7 August 21, 2019 2:05:00 afternoon org. Springframework. Context. Support. AbstractApplicationContext doClose information: Closing org.springframework.context.support.ClassPathXmlApplicationContext@3f91beef: startup date [Wed Aug 21 14:05:00 CST 2019]; root of context hierarchy destory...Copy the code

As you can see, the container first constructs the Car class, then sets its property values, then calls the init method, and finally calls the deStory method when the container is closed. Note that the initialization and destruction methods in Car do not have to be written as init and deStory. The method names can be arbitrary, as long as the initialization and destruction methods are specified at configuration time.

For life cycle management of beans, the Spring framework gives us a more fine-grained operation — the post-processor. The Bean postprocessor allows additional processing of the bean before and after the invocation of the initialization method. Moreover, it can process all bean instances in the IOC container one by one, rather than a single instance, and is typically used to check the correctness of bean properties or to change bean properties according to specific criteria. The life cycle of a bean after the bean postprocessor is changed as follows:

  1. Bean instances are created through a constructor or factory method
  2. Sets values for the bean’s properties and references to other beans
  3. Pass the bean instance to rear bean processors postProcessBeforeInitialization method
  4. Call the bean’s initialization method
  5. Pass the bean instance to rear bean processors postProcessAfterInitialization method
  6. The bean is ready to use
  7. The bean’s destruction method is called when the container is closed

So how do you implement a post-processor? Create a class that implements the interface BeanPostProcessor:

package com.itcast.spring.bean.cycle;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("postProcessAfterInitialization... :" + bean + "," + beanName);
		return bean;
	}

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("postProcessBeforeInitialization... :" + bean + "," + beanName);
		returnbean; }}Copy the code

Then add the configuration for the post-processor to the configuration file:

<! -- Configure the afterprocessor for the bean -->
<bean class="com.itcast.spring.bean.cycle.MyBeanPostProcessor"></bean>
Copy the code

This is a special bean, so you don’t need to specify an ID, and Spring will automatically look for the bean for processing. Leave the rest of the code unchanged, and rerun the test code:

Constructor... setBrand... postProcessBeforeInitialization... :com.itcast.spring.bean.cycle.Car@77caeb3e,car init... postProcessAfterInitialization... : com. Itcast. Spring. Beans. Cycle. Car @ 77 caeb3e, Car com. Itcast. Spring. Bean. The cycle. The Car @ 77 caeb3e August 21, 2019 2:17:28 afternoon org. Springframework. Context. Support. AbstractApplicationContext doClose information: Closing org.springframework.context.support.ClassPathXmlApplicationContext@3f91beef: startup date [Wed Aug 21 14:17:28 CST 2019]; root of context hierarchy destory...Copy the code

At this point, you have more control over the bean lifecycle.

FactoryBean implements configuration beans

Spring gives us a number of ways to configure beans, and FactoryBean is one of the most common ways to configure beans. How does that work? Create a class to implement the FactoryBean interface:

package com.itcast.spring.bean.factorybean;

import org.springframework.beans.factory.FactoryBean;

public class CarFactoryBean implements FactoryBean<Car> {

	@Override
	public Car getObject(a) throws Exception {
		return new Car("BMW".480000);
	}

	@Override
	publicClass<? > getObjectType() {return Car.class;
	}

	@Override
	public boolean isSingleton(a) {
		return true; }}Copy the code

You need to implement three methods that return the object instance, the object type, and whether the object is a singleton. In the configuration file:


      
<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="car" class="com.itcast.spring.bean.factorybean.CarFactoryBean">
		
	</bean>
	
</beans>
Copy the code

Write test code:

public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("beans-beanfactory.xml");
		Car car = (Car) ctx.getBean("car");
		System.out.println(car);
}
Copy the code

Running result:

The Car [brand = BMW, price = 480000.0]Copy the code

The bean configured by such a method is an instance of the class that implements the FactoryBean interface, and the result is the instance returned by the getObject method.

The annotation implements the configuration Bean

Beans can also be configured through annotations in Spring, but before that, we have to look at component scanning in Spring. Component scanning: Spring automatically scans, detects, and instantiates annotated components from the classpath path. Specific components include:

  • @Component: Basic annotation that identifies a spring-managed Component
  • Respository: Identifies the persistence layer component
  • @service: Identifies business layer components
  • @controller: Identifies presentation layer components

Spring has a default naming policy for scanned components: use unqualified class names, lowercase the first letter, or identify the component name in annotations by the value attribute value. Although each annotation corresponds to a component, Spring does not accurately identify the hierarchical distribution in the project, which means that these annotations are actually free to use, but for the sake of specification, they are used in the project according to this standard. After we use the specific annotation on the component class, we need to declare <context:component-scan> in the Spring configuration file and set the base-package property in the node. This property specifies the base class package to be scanned. The Spring container will scan all classes under this base class package and its subpackages. Spring manages these classes when it finds corresponding annotations in them. If you only want to scan for specific classes and not all classes in the base package, you can use the resource-pattern attribute to filter for specific classes, for example:

<context:component-scan
	base-package="com.itcast.spring.bean.annotation"
	resource-pattern="repository/*.class">
</context:component-scan>
Copy the code

It will scan only the classes in the Repository package. The <context: included-filter > and <context: exclud-filter > child nodes also support multiple types of filter expressions. <context: included-filter > can specify which components to include the specified expression; <context: exclud-filter > specifies which components to exclude from the specified expression.