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 创建对象是从上往下创建。

二、容器中添加组件的方法

  1. 通过@Bean
  2. 通过@import (在springboot源码中常见,导入第三方组件)
  3. 通过包扫描@CompentScan +@Controller @Service @Respository @compent【我们自己写的代码常用方式】
  4. 通过实现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
结果成功
在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值