Spring工作常用方法
文章目录
前言
主要记录下,在工作中Spring常用的一些注解方法
工程架构如下
pom文件如下
<?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>
<groupId>com.cch</groupId>
<artifactId>demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.4.RELEASE</spring-boot.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</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>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
<encoding>UTF-8</encoding>
</configuration>
</plugin>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.4.RELEASE</version>
<configuration>
<mainClass>com.cch.demo.DemoApplication</mainClass>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
一、XML配置和配置类形式
1.1 XML配置形式
现在非主流了
在resource目录下创建app.xml
配置如下
<?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="person" class="com.cch.demo.domain.Person"></bean>
</beans>
在测试DemoApplicationTests类进行测试
@SpringBootTest(classes = DemoApplication.class)
public class DemoApplicationTests {
@Test
public void classPathXmlTest(){
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("app.xml");
Person person = (Person) ctx.getBean("person");
System.out.println(person);
}
}
结果如下
获取到bean对象
1.2 配置类配置
1.2.1 普通配置
主流 的方式
在config 包下创建AppConfig
代码如下
/**
* @Configuration 表明这是一个配置类,之前是通过xml读取的配置,现在通过这里读取
* @Author chenchanghui
* @date 2020/11/26 15:43
*/
@Configuration
public class AppConfig {
/**
* @Bean 这个注解表明产生一个bean对象,像xml文件里面的<bean><bean/>标签
* @return
*/
@Bean
public Person person(){
return new Person();
}
}
在测试DemoApplicationTests类进行测试
/**
* AnnotationConfigApplicationContext 和 ClassPathXmlApplicationContext都是spring的容器
* AnnotationConfigApplicationContext 通过注解配置类的 spring 上下文
* ClassPathXmlApplicationContext 通过xml文件获取spring的上下文
*/
@Test
public void annotationConfigTest() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
Person person = (Person) ctx.getBean("person");
System.out.println(person);
}
结果如下
1.2.2 包扫描
概念总览
@ComponentScan.Filter type的类型
a)注解形式的FilterType.ANNOTATION @Controller @Service @Repository @Compent
b)指定类型的 FilterType.ASSIGNABLE_TYPE @ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value ={TulingService.class})
c)aspectj类型的 FilterType.ASPECTJ(不常用)
d)正则表达式的 FilterType.REGEX(不常用)
e)自定义的 FilterType.CUSTOM
AppConfig配置如下
//@ComponentScan(basePackages = {"com.cch.demo.dao"}) 表示扫描dao的组件
@ComponentScan(basePackages = {"com.cch.demo.dao"})
@Configuration
public class AppConfig
在测试DemoApplicationTests类进行测试
@Test
public void componentScanTest(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
结果如下:
1.2.2.1 包扫描排除过滤
配置类
appConfig
//过滤@Controller注解的组件
@ComponentScan(basePackages = {"com.cch.demo"}, excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION, value = {Controller.class})})
@Configuration
public class AppConfig {
/**
* @return
* @Bean 这个注解表明产生一个bean对象,像xml文件里面的<bean><bean/>标签
*/
@Bean
public Person person() {
return new Person();
}
}
测试
DemoApplicationTests
@Test
public void componentScanTest(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
结果如下:
配置类
appConfig
//过滤指定的类
@ComponentScan(basePackages = {"com.cch.demo"}, excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {DemoService.class})})
@Configuration
public class AppConfig {
/**
* @return
* @Bean 这个注解表明产生一个bean对象,像xml文件里面的<bean><bean/>标签
*/
@Bean
public Person person() {
return new Person();
}
}
测试
DemoApplicationTests
@Test
public void componentScanTest(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
结果如下
1.2.2.1 包扫描包含过滤
appConfig配置类如下:
//一定要把useDefaultFilters 设置为false 不然不生效
@ComponentScan(basePackages = {"com.cch.demo"}, includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE,value = DemoService.class)},useDefaultFilters = false)
@Configuration
public class AppConfig {
/**
* @return
* @Bean 这个注解表明产生一个bean对象,像xml文件里面的<bean><bean/>标签
*/
@Bean
public Person person() {
return new Person();
}
}
测试类
DemoApplicationTests
@Test
public void componentScanTest(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
测试结果如下:
包含了demoService,其他controller和repository不包含
1.2.2.2 包扫描包含过滤,自定义过滤器
配置类
appConfig
@ComponentScan(basePackages = {"com.cch.demo"}, includeFilters = {@ComponentScan.Filter(type = FilterType.CUSTOM,value = DemoFilter.class)},useDefaultFilters = false)
@Configuration
public class AppConfig {
/**
* @return
* @Bean 这个注解表明产生一个bean对象,像xml文件里面的<bean><bean/>标签
*/
@Bean
public Person person() {
return new Person();
}
}
自定义过滤器
DemoFilter
import org.springframework.core.type.ClassMetadata;
import org.springframework.core.type.classreading.MetadataReader;
import org.springframework.core.type.classreading.MetadataReaderFactory;
import org.springframework.core.type.filter.TypeFilter;
import java.io.IOException;
/**
* @Author chenchanghui
* @date 2020/11/27 17:19
*/
public class DemoFilter implements TypeFilter {
@Override
public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
ClassMetadata classMetadata = metadataReader.getClassMetadata();
if(classMetadata.getClassName().contains("Repository")){
return true;
}
return false;
}
}
测试类
DemoApplicationTests
测试结果如下:
只包含了repository 过滤了controller 和service
1.3 Bean作用域
单例模式下是饿汉式立即加载,多例模式下是懒汉加载
默认情况下
@Bean 是单例模式
@Bean
public Person person() {
return new Person();
}
多例模式
@Bean
@Scope(value = "prototype")
public Person person() {
return new Person();
}
单例懒加载
@Bean
@Lazy
public Person person() {
return new Person();
}
1.4 @Conditional
配合@Bean ,满足条件的话,才创建对应的Bean对象
在domain包下创建
public class A {
}
在appConfig配置类中
@ComponentScan(basePackages = {"com.cch.demo"})
@Configuration
public class AppConfig {
/**
* 创建位置有关系,如果在person()方法下面创建,
* 则person对象创建需要a对象的条件就不满足,
* 则person对象将不会创建
* @return
*/
@Bean
public A a(){
return new A();
}
/**
* @return
* @Bean 这个注解表明产生一个bean对象,像xml文件里面的<bean><bean/>标签
*/
@Bean
@Conditional(value = DemoCondition.class)
public Person person() {
return new Person();
}
}
测试类
DemoApplicationTests
@Test
public void componentScanTest(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
结果如下:
如果条件需要的bean “a” 在配置文件写在下方,则a对象会创建,但是person对象就不会创建,说明,spring 创建对象是从上往下创建。
二、容器中添加组件的方法
- 通过@Bean
- 通过@import (在springboot源码中常见,导入第三方组件)
- 通过包扫描@CompentScan +@Controller @Service @Respository @compent【我们自己写的代码常用方式】
- 通过实现FactoryBean接口【如sqlsessionBean】
2.1下面聊下FactoryBean这种方式
通过FactoryBean创建的对象,是调用FactoryBean接口的getObject()方法
在domain包下创建B类
@Data
public class B {
private String id;
public B(String id) {
this.id = id;
}
}
工厂实现类
public class BFactory implements FactoryBean<B> {
@Override
public B getObject() throws Exception {
return new B("11111111");
}
@Override
public Class<?> getObjectType() {
return B.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
appConfig配置类
@ComponentScan(basePackages = {"com.cch.demo"})
@Configuration
public class AppConfig {
@Bean
public BFactory b(){
return new BFactory();
}
}
测试类
DemoApplicationTests
@Test
public void annotationConfigTest() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
B b = (B) ctx.getBean("b");
System.out.println(b);
}
测试结果如下:
三、Bean的初始调用方法和消耗调用方法
3.1 @Bean(initMethod = “init方法名称”,destroyMethod = “destroy方法名称”)
新建Man类
public class Man {
public void init() {
System.out.println("init方法被调用。。。。。。。。。。");
}
public void destroy() {
System.out.println("destroy方法被调用");
}
}
appCofig配置类如下
@Configuration
public class AppConfig {
@Bean(initMethod = "init",destroyMethod = "destroy")
public Man man(){
return new Man();
}
}
测试类
DemoApplicationTests
@Test
public void annotationConfigTest() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
Man man = (Man) ctx.getBean("man");
System.out.println(man);
ctx.destroy();
}
3.2 通过 InitializingBean和DisposableBean
domain包下
Woman类如下:
@Component
public class Woman implements InitializingBean, DisposableBean {
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean 的 destroy 方法被调用。。。。。。。。。");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean 的 afterPropertiesSet被调用。。。。。。。。。。");
}
}
appConfig配置类如下:
@ComponentScan(basePackages = {"com.cch.demo"})
@Configuration
public class AppConfig {
}
测试类
DemoApplicationTests
@Test
public void annotationConfigTest() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
Woman woman = (Woman) ctx.getBean("woman");
System.out.println(woman);
ctx.destroy();
}
测试结果如下:
3.3 @PostConstruct 和@PreDestory
domain包新增
@Component
public class Desk {
@PostConstruct
public void init(){
System.out.println("@PostConstruct 初始化 被调用。。。。。。。。。");
}
@PreDestroy
public void destroy(){
System.out.println("@PreDestroy 注销 被调用。。。。。。。。。");
}
}
appConfig配置类如下:
@ComponentScan(basePackages = {"com.cch.demo"})
@Configuration
public class AppConfig {
}
DemoApplicationTests测试类如下:
@Test
public void annotationConfigTest() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
Desk desk = (Desk) ctx.getBean("desk");
System.out.println(desk);
ctx.destroy();
}
结果如下:
四、读取配置文件 @Value +@PropertySource来
application.properties内容如下:
name=xxx
domain包下增加Book类
@Data
@Component
public class Book {
@Value("${name}")
private String name;
@Value("#{30-3.3}")
private double price;
}
appConfig 配置类
@ComponentScan(basePackages = {"com.cch.demo"})
@PropertySource(value = {"classpath:application.properties"})
@Configuration
public class AppConfig {
}
测试类如下:
DemoApplicationTests
@Test
public void annotationConfigTest() {
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
Book book = (Book) ctx.getBean("book");
System.out.println(book);
ctx.destroy();
}
测试结果如下:
五、@Profile注解使用不同环境配置
appConfig配置类如下:
@ComponentScan(basePackages = {"com.cch.demo"})
@Configuration
public class AppConfig {
@Bean
@Profile("test")
public Man man(){
return new Man();
}
@Bean
@Profile("dev")
public Woman woman(){
return new Woman();
}
}
DemoApplicationTests测试类如下
#JVM 参数指定环境
-Dspring.profiles.active=dev|test|pro
这里指定激活dev环境,则woman对象会被创建出来,而man对象不会
@Test
public void componentScanTest(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
结果如下:
六、自动装配使用
先说结论:
自动装配首先时按照类型进行装配,若在IOC容器中发现了多个相同类型的组件,那么就按照 属性名称来进行装配
6.1对应的注入类不存在
dao包下新建DemoRepositoryInterface
@ComponentScan(basePackages = {"com.cch.demo"})
@Configuration
public class AppConfig {
}
public interface DemoRepositoryInterface {
}
service包下新建DemoService,注入DemoRepositoryInterface
@Service
public class DemoService {
@Autowired
private DemoRepositoryInterface demoRepositoryInterface;
}
在DemoApplicationTests测试类中执行如下测试
@Test
public void componentScanTest(){
AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
String[] beanDefinitionNames = ctx.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
报错如下
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoService': Unsatisfied dependency expressed through field 'demoRepositoryInterface'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.cch.demo.dao.DemoRepositoryInterface' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
重新运行DemoApplicationTests测试方法componentScanTest
结果如下
在@Autowired(required = false)加上required = false 不管这个类存不存在都不影响
@Service
public class DemoService {
@Autowired(required = false)
private DemoRepositoryInterface demoRepositoryInterface;
}
重新运行DemoApplicationTests测试方法componentScanTest
结果如下
6.2 存在多个指定注入bean类型的对象
dao包下新建DemoRepository和DemoRepository2实现该接口
public class DemoRepository implements DemoRepositoryInterface{
}
public class DemoRepository2 implements DemoRepositoryInterface {
}
因为@Autowire是根据类型判断,当该类型下有多个的时候,会报错
核心错误如下
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'demoService': Unsatisfied dependency expressed through field 'demoRepositoryInterface'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.cch.demo.dao.DemoRepositoryInterface' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Qualifier(value=dp1), @org.springframework.beans.factory.annotation.Autowired(required=true)}
6.3 指定bean名称
为了解决该方法。需要在注入的类上写上@Qualifier(“指定注入的bean名称”)
DemoService 在注入 @Autowired增加@Qualifier(“demoRepository”)指定注入bean的名称
@Service
public class DemoService {
@Qualifier("demoRepository")
@Autowired
private DemoRepositoryInterface demoRepositoryInterface;
}
重新运行DemoApplicationTests 6.1节的测试方法componentScanTest
结果成功
本文地址:https://blog.csdn.net/sinat_36759535/article/details/110228047