Spring核心
组件扫描 component scanning
@ComponentScan注解是一个Spring的注解,用于扫描包上的注解将组件加载到IOC容器中。
作用:扫描被@Controller、@Service、@Repository、@Component等注解标注的类。
@ComponentScan注解只能使用在有@Configuration配置注解的地方,因为component-scan标签必须存在于xml配置文件中;而在脱离xml使用时,需要使用带有在@Configuration配置注解上。
简而言之
@Configuration = xml 文件
@ComponentScan用来代替xml文件中的配置control、Service、Repository、Component的配置语句
<context:component-scan base-package="com.thg.entity"/>
例如以上语句就扫描了entity包下的所有类,用@ComponentScan代替就是
@Configuration @ComponentScan(basePackages = {"com.thg.entity"}) public class Config { }
Component注解
把普通pojo实例化到spring容器中,相当于配置文件中的
<bean id="" class=""/>
使用方法:
- 在pojo类上加入@Component关键字
- 如果使用@Configuration配置,则加入@ComponentScan(basePackages = {“com.thg.entity”})扫描包
- 如果使用xml配置,则加入 <context:component-scan base-package=“com.thg.entity”/>
Autowire注解
如果说Component=
那么Autowire=<construct-args + <propority
一般@Autowire配合@Component一起使用
- @Component注册bean
- @Autowire注入依赖
Autowire有三种注入方式
- 属性注入
- setter注入
- 构造器注入
Qualifier 注解
@Qualifier一般与@Autowire一起用,当我们需要注入的对象有多个时,为了避免歧义装配错了,采用@Qualifier指明需要装配的bean id/name
public class Profile {
@Autowired
@Qualifier("student1")
private Student student;
public Profile(){
System.out.println("Inside Profile constructor." );
}
public void printAge() {
System.out.println("Age : " + student.getAge() );
}
public void printName() {
System.out.println("Name : " + student.getName() );
}
}
Bean注解
Bean注解和Component有些类似
Component的作用是标明该类需要被注入,然后使用ComponentScan扫描注入
而Bean注解也是注入,但是他是放在Config类中,去处理某些无法由Component处理的注入的情形
- 内部类,无法Component
- Component一个类对应一个bean,如果一个类需要多个Component的时候,使用@bean
比如我需要注入一个Map,显然我不可能跑源码里去注入Map
如果去写xml又显得头重脚轻多此一举,这时bean就起到作用了
@Configuration @ComponentScan(basePackages = {"com.thg.entity"}) public class Config { @Bean public Map<String,String> getMap(){ Map<String,String> map = new HashMap<>(); map.put("no1","thg"); map.put("no2","thh"); System.out.println("map is 注入"); return map; } }
取别名
如上,@bean会将getMap注入到ioc容器中,如果你想换个名字,这样就行了
@Bean(name = "map")
创建函数及销毁函数
@Bean(initMethod = "init", destroyMethod = "cleanup" )
Config配置
我们使用@Configuration去代替xml文件
@ComponentScan
- 作用:用来扫描control、Service、Repository、Component的配置语句
- 等价于<context:component-scan base-package=“xxx”/>
- 代码位置:放在Config类上
@Import
-
作用:@import 注解允许从另一个配置类中加载 @Bean 定义。
-
代码位置:放在Config类上
@Profile
指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件
就比如数据库连接池这些,在不同环境下加载不同的属性
需要在主函数拿到context之后指定即可
applicationContext.getEnvironment().setActiveProfiles("dev","master");
Spring Boot
SpringBootApplication核心注解
源码如下
package org.springframework.boot.autoconfigure;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan(excludeFilters = {
@Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),
@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })
public @interface SpringBootApplication {
......
}
package org.springframework.boot;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Configuration
public @interface SpringBootConfiguration {
}
简而言之,SpringBootApplication注解等效于下面三个注解的合集
- @EnableAutoConfiguration:启用 SpringBoot 的自动配置机制
- @ComponentScan: 扫描被@Component (@Service,@Controller)注解的 bean,注解默认会扫描该类所在的包下所有的类。
- @Configuration:允许在 Spring 上下文中注册额外的 bean 或导入其他配置类
后两个注解都很熟悉,我们来康康@EnableAutoConfiguration
@EnableAutoConfiguration
默认会扫描与项目启动类同级或者更低级目录下的所有使用@Configuration注解的类
意思就是@Configuration最好放在同级别下,否则你要加入@Improt把你写的config加入进来
config实现的三种方式
- 直接在SpringBootApplication上加入你需要的东西,因为SpringBootApplication本质就是一个config类
- 在SpringBootApplication的统计目录或者下级目录下实现一个config类,并用@Configuration标注
- 在别的地方配置Config 然后使用@Import加入SpringBootApplication
Application配置文件
springboot引入了application.properties和application.yaml来简化配置过程
spring:
application:
name: "thg"
datasource:
url: jdbc:mysql://sh-cynosdbmysql-grp-bbhdi89q.sql.tencentcdb.com:21590/pic?serverTimezone=UTC
driver-class-name: com.mysql.jdbc.Driver
username: root
password: thgXXXXXX!
server:
port: 8081
就比如上面的配置,不需要注入任何的bean,就可以直接在代码中使用
@Autowired
JdbcTemplate jdbcTemplate;
属性嵌套
app.name=MyApp
app.description=${app.name}
Yaml文件
基本语法
对象:
father:
child1: Jack
child2: Bob
数组:
animals:
- Cat
- Dog
- Goldfish
或者
animals: [ 'Cat', 'Dog', 'Goldfish' ]
null值:
用~表示null
@ConfigurationProperties实现自动装配
@ConfigurationProperties(prefix = "my-person")
@Component
@Data
public class Person {
private String userName;
private Boolean boss;
private Date birth;
private Integer age;
private Pet pet;
private String[] interests;
private List<String> animal;
private Map<String, Object> score;
private Set<Double> salarys;
private Map<String, List<Pet>> allPets;
}
my-person:
user-name: CodeTiger
boss: true
birth: 1996/11/29
# 可以使用random来生成各种不同类型的随机值
age: ${random.int}
pet:
name: tomcat
weight: 100
interests: [basketball, football]
animal:
- jerry
- tom
score:
english:
first: 30
second: 40
third: 50
math: [131,140,148]
chinese: {first: 128, second: 136}
salarys: [3999,4999.98,5999.99]
allPets:
sick:
- {name: tom}
- {name: jerry,weight: 47}
health: [{name: mario,weight: 47}]
注意:@ConfigurationProperties的本质是使用setter注入,所以必须要有setter方法不然没法注入
关于引入其他yaml文件的问题
我们可以注意到,当我们要引用其他配置文件时,使用@PropertySource注解来引用
但是这个注解无法配置yaml文件,所以有两种解决方案
- 其他配置文件全部用properties来实现
- 自己实现factory来转换yaml
自定义factory如下
import org.springframework.beans.factory.config.YamlPropertiesFactoryBean;
import org.springframework.core.env.PropertiesPropertySource;
import org.springframework.core.env.PropertySource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.core.io.support.PropertySourceFactory;
import org.springframework.lang.Nullable;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.Properties;
public class YamlPropertySourceFactory implements PropertySourceFactory {
@Override
public PropertySource<?> createPropertySource(@Nullable String name, EncodedResource resource) throws IOException {
Properties propertiesFromYaml = loadYamlIntoProperties(resource);
String sourceName = name != null ? name : resource.getResource().getFilename();
return new PropertiesPropertySource(sourceName, propertiesFromYaml);
}
private Properties loadYamlIntoProperties(EncodedResource resource) throws FileNotFoundException {
try {
YamlPropertiesFactoryBean factory = new YamlPropertiesFactoryBean();
factory.setResources(resource.getResource());
factory.afterPropertiesSet();
return factory.getObject();
} catch (IllegalStateException e) {
// for ignoreResourceNotFound
Throwable cause = e.getCause();
if (cause instanceof FileNotFoundException)
throw (FileNotFoundException) e.getCause();
throw e;
}
}
}
使用时:
@Component
@PropertySource(value = "my.yaml" , factory = YamlPropertySourceFactory.class)
@ConfigurationProperties(prefix = "user")
@Data
public class User {
private int age;
private String name;
}
Spring配置
Maven依赖
spring核心
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>5.3.20</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.20</version>
</dependency>
SpringBoot核心
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
JDBC以及mysql
//用spring时用这个
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.20</version>
</dependency>
//用springboot用这个
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.25</version>
</dependency>
配置JDBC
spring其实经历了从xml->config->springboot的过程,所以配置数据库连接也有三种方式
xml原始版
<!-- 1.数据库配置 -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${driverClassName}"></property>
<property name="url" value="${url}"></property>
<property name="password" value="${password}"></property>
<property name="username" value="${username}"></property>
</bean>
<!-- 2.配置JDBC帮助类 -->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!-- 3.加载资源文件 -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:spring/dbconfig.properties</value>
</list>
</property>
</bean>
<bean id="demo" class="com.dmeo.jdbc.JDBCTest"></bean>
config版本
我们看到xml配置中
- propertyConfigurer可以用 @PropertySource(“classpath:/dbconfig.properties”)代替
url=jdbc:mysql://sh-cynosdbmysql-grp-bbhdi89q.sql.tencentcdb.com:21590/pic?serverTimezone=UTC
driverClassName=com.mysql.jdbc.Driver
password=thg1998913!
user=root
@Configuration
@ComponentScan(basePackages = {"com.thg.entity"})
@PropertySource(value = {"dbconfig.properties"})
public class Config {
@Autowired
DriverManagerDataSource dataSource;
@Bean
public DriverManagerDataSource dataSource(@Value("${url}") String url,@Value("${driverClassName}") String driverClassName,@Value("${user}")String username, @Value("${password}")String passwd){
DriverManagerDataSource database = new DriverManagerDataSource() ;
database.setUrl(url); //设置url
database.setDriverClassName(driverClassName);
database.setUsername(username); //设置账号
database.setPassword(passwd); //设置密码
return database;
}
@Bean
public JdbcTemplate jdbcTemplate(){
return new JdbcTemplate(dataSource);
}
}
这里有一个需要注意的地方
就是@Value(“${user}”)String username
我开始是使用@Value(“${username}”)String username
后面一直连接不上的原因是无论你怎么改变dbconfig.properties的内容始终username永远定格在"thg"
我就怀疑是spring内置了一个变量叫username,导致我@Value出来的不是我properties文件中的内容
于是我将username改为user后发现可以成功连接上
springboot配置
我们知道springboot自动装配
使用application.properties配置
spring.datasource.url=jdbc:mysql://sh-cynosdbmysql-grp-bbhdi89q.sql.tencentcdb.com:21590/pic?serverTimezone=UTC
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.password=thg1998913!
spring.datasource.username=root
使用yaml配置其实是一样的不在累叙