inversion of control
初学Java可能使用new创建对象。但spring通过描述来创建对象。
spring boot不建议使用xml,而是通过注解描述生成对象。
spring中每一个需要管理的对象称为bean,spring管理这些bean的容器,称为ioc容器。
ioc容器需要具备2个基本功能:
1.通过描述发布和获取bean
2.通过描述完成bean直接的依赖关系
在spring中,所有的ioc容器都要实现顶级容器接口BeanFactory
接口中有多个getBean方法,意味着允许我们按照类型或者名称获取bean
isSingleton判断bean是否为单例
ioc容器中默认bean都为单例,即getBean返回同一个对象
与之相反的是isPrototype方法,如果返回true。那么getBean会创建一个新的Bean返回。
beanFactory拥有子接口ApplicationContext
简单体验一下applicationContext
package com.springboot.chapter3.pojo;
/**
* @author KNOE
* @date 2020-09-21 12:15
*/
public class User {
private Long id;
private String userName;
private String note;
// alt+insert
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
package com.springboot.chapter3.config;
import com.springboot.chapter3.pojo.User;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author KNOE
* @date 2020-09-21 12:20
*/
@Configuration
public class AppConfig {
@Bean(name = "user")
public User initUser() {
User user = new User();
user.setId(1L);
user.setUserName("user_name_1");
user.setNote("note_1");
return user;
}
}
@Configuration表示这个一个配置文件,spring会根据他来生成ioc容器装配bean
@Bean表示讲该方法返回的pojo装配到ioc容器中。其属性name定义bean的名称,
如果不写,方法名就是bean的名称
package com.springboot.chapter3.config;
import com.springboot.chapter3.pojo.User;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author KNOE
* @date 2020-09-21 12:23
*/
public class IoCTest {
private static Logger log = LogManager.getLogger(IoCTest.class);
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx
= new AnnotationConfigApplicationContext(AppConfig.class);
User user = ctx.getBean(User.class);
log.info(user.getId());
}
}
将配置文件appConfig传递给一个构造方法。于是可以用getBean方法获取pojo
注意log4j2.13的全新写法
就像这样参考
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
private static Logger logger = LogManager.getLogger(myClass.class);
可以看到bean的属性能够输出出来
通过component装配bean
把user改成这样
package com.springboot.chapter3.pojo;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
/**
* @author KNOE
* @date 2020-09-21 12:15
*/
@Component("user")
public class User {
@Value("1")
private Long id;
@Value("user_name_1")
private String userName;
@Value("note_1")
private String note;
// alt+insert
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public String getNote() {
return note;
}
public void setNote(String note) {
this.note = note;
}
}
component表面要被ioc容器扫描装配。如果不配置name
会自动把类名小写作为bean名称
@Value指定具体的值,注入对应属性
改造appConfig
package com.springboot.chapter3.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
/**
* @author KNOE
* @date 2020-09-21 12:20
*/
@Configuration
@ComponentScan("com.springboot.chapter3.*")
public class AppConfig {
}
@ComponentScan会让类扫描,这样就能删掉创建对象方法
但是默认只能扫描本包和子包
需要特别定义扫描的包
@ComponentScan(value = "com.springboot.chapter3.*",
excludeFilters = {@ComponentScan.Filter(classes = {myClass.class})})
还可以这样写,排除不想注入的类
自定义第三方bean
但是这不代表bean没用了。经常需要引入第三方的包,希望把其中的类也放到ioc容器中。这时@Bean注解就有用了。因为componentScan顶多扫描项目里的类,第三方的类都不在项目文件里,也没法扫描,也加不了@Component
package com.springboot.chapter3.pojo;
import org.springframework.stereotype.Service;
/**
* @author KNOE
* @date 2020-09-21 16:11
*/
@Service
public class UserService {
public void print(User user) {
System.out.println("user = " + user.getId());
}
}
新写一个service类
<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>springboot</groupId>
<artifactId>chapter3</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>chapter3</name>
<description>Chapter3 project for Spring Boot</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<exclusions>
<exclusion>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-dbcp2</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
在xml里加入sql的依赖
通过bean引入第三方bean,同时排除service类
使用dbpc生成数据源
package com.springboot.chapter3.config;
import org.apache.commons.dbcp2.BasicDataSourceFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;
import javax.sql.DataSource;
import java.util.Properties;
/**
* @author KNOE
* @date 2020-09-21 12:20
*/
@Configuration
@ComponentScan(value = "com.springboot.chapter3.*",
excludeFilters = {@ComponentScan.Filter(classes = {Service.class})})
public class AppConfig {
@Bean(name = "dataSource")
public DataSource getDataSource() {
Properties props = new Properties();
props.setProperty("driver", "com.driver.jdbc.Driver");
props.setProperty("url", "jdbc:mysql://localhost:3306/testdb");
props.setProperty("username", "root");
props.setProperty("password", "123456");
DataSource dataSource = null;
try{
dataSource = BasicDataSourceFactory.createDataSource(props);
}catch (Exception e) {
e.printStackTrace();
}
return dataSource;
}
}
测试一下
package com.springboot.chapter3.config;
import com.springboot.chapter3.pojo.User;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import javax.sql.DataSource;
/**
* @author KNOE
* @date 2020-09-21 12:23
*/
public class IoCTest {
private static Logger log = LogManager.getLogger(IoCTest.class);
public static void main(String[] args) {
AnnotationConfigApplicationContext ctx
= new AnnotationConfigApplicationContext(AppConfig.class);
User user = ctx.getBean(User.class);
log.info(user.getId());
DataSource dataSource = ctx.getBean(DataSource.class);
log.info(dataSource.getClass());
}
}
没有任何问题