Article directory
1. Spring's IoC core container
Get the object by id according to the xml configuration file
pom.xml file import spring dependency:
<?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>springfactory</artifactId> <version>1.0-SNAPSHOT</version> <packaging>jar</packaging> <dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.12.RELEASE</version> </dependency> </dependencies> </project>
Create the bean.xml file and submit the creation of the object to spring for management:
<?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="accountService" class="com.zcj2.service.impl.AccountServiceImpl" ></bean> <bean id="accountDao" class="com.zcj2.dao.impl.AccountDaoImpl"></bean> </beans>
Use steps:
- 1. Get the IoC core container of spring
- 2. Get the instantiated object by id
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); IAccountService as = (IAccountService) ac.getBean("accountService"); IAccountDao adao = ac.getBean("accountDao",IAccountDao.class); System.out.println(as); System.out.println(adao);
Three common implementation classes of ApplicationContext:
- ClassPathXmlApplicationContext: the configuration file under the classpath can be loaded. The configuration file must be under the classpath. (more often)
- Filesystemxlapplicationcontext: you can load the configuration file under any path of the disk (access permission is required)
- Annotation config application context: read annotation creation container
Problems caused by two interfaces of ApplicationContext:
-
ApplicationContext: when creating the core container, the policy of creating objects is: load immediately. As soon as you finish reading the configuration file, create the objects configured in the configuration file. The singleton object is applicable. This interface is generally used.
-
BeanFactory: when creating the core container, the policy of creating objects is: delay loading. When you get an object with an id, you create it. Multiple objects applicable
Resource resource = new ClassPathResource("bean.xml"); BeanFactory factory = new XmlBeanFactory(resource); IAccountService as1 = (IAccountService) factory.getBean("accountService"); System.out.println(as1);
2. Details of spring's bean management
1. Three ways to create bean s
-
1. Use default constructor
When the bean tag is used in the spring configuration file with id and class attributes and no other attributes and tags, the default constructor is used to create the bean object. At this time, if the class does not have a constructor, the object cannot be created
<bean id="accountService" class="com.zcj3.service.impl.AccountServiceImpl" ></bean>
public class AccountServiceImpl implements IAccountService { //That would be a mistake public AccountServiceImpl(String name){ System.out.println("Object created"); } public AccountServiceImpl(){ System.out.println("Object created"); } public void saveAccount() { System.out.println("Save account method executed"); } }
-
2. Create an object using the common methods in the factory (use the methods in a class to create an object and store it in the spring container) (generally applicable to classes to create other imported jar packages, which have already written constructors, but we can't modify their source code)
<bean id="instanceFactory" class="com.zcj3.factory.InstanceFactory"></bean> <bean id="accountService" factory-bean="instanceFactory" factory-method="getService"></bean>
Factory method: the method to create the bean object. Factory bean: the id of the factory bean
public class InstanceFactory { public IAccountService getService(){ return new AccountServiceImpl(); } }
-
3. Use the static method in the factory to create the object and store it in the spring container (generally applicable to the class to create other imported jar packages. It has a written constructor, but we can't modify its source code)
<bean id="accountService" class="com.zcj3.factory.StaticFactory" factory-method="getService"></bean>
public class StaticFactory { public static IAccountService getService(){ return new AccountServiceImpl(); } }
2. Scope of bean
The bean object created by spring is singleton by default
scope property of bean tag:
- singletone (default)
- Many examples of prototype
- The request scope of request for web application
- session scope for web application
- Global session acts on the session scope (global session scope) of the cluster environment. When it is not a cluster environment, it is a session
<bean id="accountService" class="com.zcj3.service.impl.AccountServiceImpl" scope="prototype"></bean>
3. Life cycle of bean object
Single object:
-
Birth: container creation, object birth
-
Alive: the container is still alive, the object is still alive
-
Death: container destroyed, object destroyed
Container in, object in
Multiple objects:
- Birth: the spring framework creates for us when we use objects
- Live: live all the time during use
- Death: spring does not know when the object is not used, so when the object is not used for a long time and there is no other object reference, java's garbage collector recycles
<bean id="accountService" class="com.zcj3.service.impl.AccountServiceImpl" scope="singleton" init-method="init" destroy-method="destory"></bean>
public class AccountServiceImpl implements IAccountService { public AccountServiceImpl(){ System.out.println("Object created"); } public void saveAccount() { System.out.println("Save account method executed"); } public void init(){ System.out.println("Object initialized"); } public void destory(){ System.out.println("Object destroyed"); }
/** * Get the IOC core container of spring and get the object according to the id * @param args */ public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); IAccountService as = (IAccountService) ac.getBean("accountService"); IAccountService as1 = (IAccountService) ac.getBean("accountService"); System.out.println(as==as1); }
Object created Object initialized true
This is because the memory has been released before the object is destroyed
We can manually close the container:
/** * Get the IOC core container of spring and get the object according to the id * @param args */ public static void main(String[] args) { ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); IAccountService as = (IAccountService) ac.getBean("accountService"); IAccountService as1 = (IAccountService) ac.getBean("accountService"); System.out.println(as==as1); ac.close(); }
Object created Object initialized true Object destroyed
3. Dependency injection in spring
Dependency Injection
The role of IOC: reducing the coupling between programs (dependency)
Dependency management will be handed over to spring later. Currently, classes need objects of other classes. Spring provides them for us. We only need to explain them in the configuration file. Dependency maintenance is called dependency injection
Type of injected data:
- Basic types and string s
- Other bean types (beans configured in configuration files or annotations)
- Complex type, set type
How to inject data:
1. Use constructor
Constructor Arg tag. Inside the bean tag, the attributes in the tag are:
-
Type specifies the type of data to inject, which is also the type of one or some parameters in the constructor
-
Index is used to specify the data to be injected to assign values to the parameters in the constructor that specify the index location. The index location starts from 0‘
-
Name is used to assign a parameter to the specified name in the constructor (common)
The three above are used to specify which parameter in the constructor to assign
-
value is used to provide data of basic type and string type
-
ref is used to specify other bean type data. It refers to bean objects that have appeared in the ioc core container of spring
<bean id="accountService" class="com.zcj4.service.impl.AccountServiceImpl"> <constructor-arg name="name" value="test"></constructor-arg> <constructor-arg name="age" value="18"></constructor-arg> <constructor-arg name="birthday" ref="now"></constructor-arg> </bean> <!--Configure a date object--> <bean id="now" class="java.util.Date"></bean>
public class AccountServiceImpl implements IAccountService { //If it's constantly changing data, it's not suitable for the way of injection private String name; private Integer age; private Date birthday; public AccountServiceImpl(String name,Integer age,Date birthday){ this.name =name; this.age = age; this.birthday =birthday; } public void saveAccount() { System.out.println("Save account method executed"+name+","+age+","+birthday); } }
public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("bean_zcj4.xml"); IAccountService as = (IAccountService) ac.getBean("accountService"); as.saveAccount(); }
test,18,Wed Mar 11 14:24:08 CST 2020 is executed for saving account method
Advantage: when getting the bean object, it is necessary to inject data, otherwise the object cannot be created successfully
Disadvantage: it changes the instantiation method of bean objects. When we create objects, if we can't use these data, we must also provide
2. Use set method (more commonly used)
property tag. Inside the bean tag, the properties in the tag are:
- Name: used to specify the name of the set method called during injection, and the remaining fields after the set is removed
- value: provide data of basic type and string type
- ref: used to specify other bean type data. It refers to bean objects that have appeared in the ioc core container of spring
<bean id="accountService" class="com.zcj4.service.impl.AccountServiceImpl"> <property name="name" value="test"></property> <property name="age" value="18"></property> <property name="birthday" ref="now"></property> </bean>
public class AccountServiceImpl implements IAccountService { //If it's constantly changing data, it's not suitable for the way of injection private String name; private Integer age; private Date birthday; public void setName(String name) { this.name = name; } public void setAge(Integer age) { this.age = age; } public void setBirthday(Date birthday) { this.birthday = birthday; } public void saveAccount() { System.out.println("Save account method executed"+name+","+age+","+birthday); } }
Advantage: there is no explicit restriction when creating objects, and you can directly use the default constructor
Disadvantage: if a member must have a value, the set method to get the object may not execute
Injection of complex type and set type:
- Label used to inject the list structure collection:
list array set - Label to inject into the map structure set:
map props - Same structure, interchangeable labels
public class AccountServiceImpl2 implements IAccountService { private String[] myStrs; private List<String> myList; private Set<String> mySet; private Map<String,String> myMap; private Properties myProps; public void setMyStrs(String[] myStrs) { this.myStrs = myStrs; } public void setMyList(List<String> myList) { this.myList = myList; } public void setMySet(Set<String> mySet) { this.mySet = mySet; } public void setMyMap(Map<String, String> myMap) { this.myMap = myMap; } public void setMyProps(Properties myProps) { this.myProps = myProps; } public void saveAccount() { System.out.println(Arrays.toString(myStrs)); System.out.println(myList); System.out.println(mySet); System.out.println(myMap); System.out.println(myProps); } }
<bean id="accountService2" class="com.zcj4.service.impl.AccountServiceImpl2"> <property name="myStrs"> <array> <value>AAA</value> <value>BBB</value> <value>AAA</value> <value>CCC</value> </array> </property> <property name="myList"> <list> <value>AAA</value> <value>BBB</value> <value>AAA</value> <value>CCC</value> </list> </property> <property name="mySet"> <set> <value>AAA</value> <value>BBB</value> <value>AAA</value> <value>CCC</value> </set> </property> <property name="myMap"> <map> <entry key="testA" value="aaa"></entry> <entry key="testB"> <value>bbbb</value> </entry> </map> </property> <property name="myProps"> <props> <prop key="testc">cccc</prop> <prop key="testd">dddd</prop> </props> </property> </bean>
public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("bean_zcj4.xml"); IAccountService as = (IAccountService) ac.getBean("accountService2"); as.saveAccount(); }
[AAA, BBB, AAA, CCC] [AAA, BBB, AAA, CCC] [AAA, BBB, CCC] {testA=aaa, testB=bbbb} {testd=dddd, testc=cccc}
3. Use notes
Profile:
<?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"> <!-- inform spring The package to be scanned when creating the container, the required label for configuration is not beans But a noun is context In namespaces and constraints--> <context:component-scan base-package="com.zcj"></context:component-scan> </beans>
@Component(value = "accountService") public class AccountServiceImpl implements IAccountService { private IAccountDao accountDao; public AccountServiceImpl(){ System.out.println("Object created"); } }
public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); IAccountService as = (IAccountService) ac.getBean("accountService"); as.saveAccount(); }
To create an annotation for an object:
-
Component
Function: used to store class objects into spring containers
Properties:
- Value: used to specify the id of the bean. When we do not write value, its default value is the current lowercase class name. If Component only needs this one attribute, it can be abbreviated as @ Component("claaName")
-
Controller used in presentation layer
-
Service in business layer
-
Repository is used in the persistence layer
As for @ Controller, @ Service, @ Repository, the spring framework provides us with clear three-tier annotations to make our three-tier objects clearer!
In fact, there is no essential difference between these four notes. If you like, you can use these four notes as one note
Annotation of injection object:
-
Autowired: automatically inject by type. As long as there is a unique bean object in the container that matches the type of variable to be injected, the injection can succeed. If the type of any bean in the IOC container does not match the type to be injected, an error is reported. If there is more than one type match in the IOC container, the match is based on the name of the variable to be injected.
Location of occurrence: either on variable or method
When using annotations, the set method is not required
@Component public class AccountDaoImpl implements IAccountDao { public void saveAccount() { System.out.println("Saving account "); } }
@Component(value = "accountService") public class AccountServiceImpl implements IAccountService { @Autowired private IAccountDao accountDao; public AccountServiceImpl(){ System.out.println("Object created"); } public void saveAccount() { accountDao.saveAccount(); } }
If the following classes appear:
@Component public class AccountDaoImpl2 implements IAccountDao { public void saveAccount() { System.out.println("Saving account "); } }
Since two classes implement the same interface IAccountDao, continuing to use such annotations will result in an error
@Autowired private IAccountDao accountDao;
You can specify the object to create by changing the variable name:
@Autowired private IAccountDao accountDaoImpl;
Or use Qualifier to specify
-
Qualifier: on the basis of injecting by class, inject by name. It cannot be used alone (with Autowired) when injecting class members, but it can be used when injecting method parameters.
Property: value, which specifies the id of the injected bean
@Autowired @Qualifier(value = "accountDaoImpl2") private IAccountDao accountDao;
-
Resource: injected directly according to the bean id, which can be used independently
Property: name, which specifies the id of the injected bean
Autowired Qualifier Resource can only inject data of other bean types. Basic type and String cannot be implemented. Collection type can only be injected through xml
-
Value: used to inject data of basic type and String type
Property: value, which is used to specify the value of the data. You can use spring's spel (that is, spring's el expression)
SpEL's way of writing: $(expression)
Used to change the scope of action:
-
Scope specifies the scope of the bean
Attribute: value, value: singleton, prototype
@Component @Scope("prototype") public class AccountDaoImpl2 implements IAccountDao { public void saveAccount() { System.out.println("Saving account "); } }
Life cycle related:
-
PreDestory: used to specify the destruction method
-
PostConstruct: used to specify the initialization method
@Component(value = "accountService") public class AccountServiceImpl implements IAccountService { @PostConstruct public void init() { accountDao.saveAccount(); } @PreDestroy public void destory() { accountDao.saveAccount(); } }
4.Spring configuration notes
- Configuration: Specifies that the current class is a configuration class
When the configuration class is created as a parameter of the annotationconfigpplicationcontext object, the annotation can be left blank.
- ComponentScan: used to specify the package to be scanned by spring when creating the container by annotation
Property: value: it has the same function as basePackages, and is used to define the package to be scanned when creating the container.
- Bean: store the return value of the current method as a bean object in spring's IOC container
Property: Name: used to specify the bean id. when it is not written, the default value is the name of the current method. When this annotation is used to configure the method, if the method has parameters, the spring framework will go to the container to find whether there are available bean objects. The search method is the same as that of autowritten
@Configuration @ComponentScan("com.zcj") public class SpringConfig { @Bean(name = "runner") public QueryRunner createQueryRunner(DataSource dataSource){ return new QueryRunner(dataSource); } @Bean(name = "dataSource") public DataSource createDataSource(){ try { ComboPooledDataSource ds = new ComboPooledDataSource(); ds.setDriverClass("com.mysql.jdbc.Driver"); ds.setJdbcUrl("jdbc:mysql://localhost:3306/eesy"); ds.setUser("root"); ds.setPassword("123456"); return ds; }catch (Exception e){ e.printStackTrace(); } return null; } }
Its function is equivalent to the following:
<bean id="accountService" class="com.zcj.service.impl.AccountServiceImpl"> <property name="accountDao" ref="accountDao"></property> </bean> <bean id="accountDao" class="com.zcj.dao.impl.AccountDaoImpl"> <property name="runner" ref="runner"></property> </bean> <bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype"> <constructor-arg name="ds" ref="dataSource"></constructor-arg> </bean> <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"> <property name="driverClass" value="com.mysql.jdbc.Driver"></property> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/eesy?3useUnicode=true&characterEncoding=utf8"></property> <property name="user" value="root"></property> <property name="password" value="123456"></property> </bean>
When getting objects, it is as follows:
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
- Import: used to import other configuration classes
Property: value: used to specify the bytecode of other configuration classes. When we use the Import annotation, the classes with Import annotation are the parent configuration classes, while the imported classes are all the child configuration classes
- PropertySource: used to specify the location of the properties file
Attribute: value: Specifies the name and path of the file, keyword: classpath, which means under the classpath
@Import(JdbcConfig.class) @PropertySource("classpath:jdbcConfig.properties") public class xxx{}
5.Spring integrates junit configuration
-
1. Import spring integration junit jar (coordinates)
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.0.2.RELEASE</version> </dependency>
-
2. Use an annotation @ Runwith provided by Junit to replace the original main method with the one provided by spring
-
3. Tell the spring runner whether the creation of spring and ioc is based on xml or annotation, and indicate the location:
@ContextConfiguration: there are two ways:
locations: specify the location of the xml file, and add the classpath keyword to indicate that it is under the classpath
classes: Specifies the location of the annotation class
@RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(classes = SpringConfiguration.class) public class AccountServiceTest { @Autowired private IAccountService as = null; @Test public void testFindAll() { //3. Implementation method List<Account> accounts = as.findAllAccount(); for(Account account : accounts){ System.out.println(account); } } }
Source: Learn – Zhang Yang 2018 black horse Spring tutorial IDEA version