Spring学习笔记【十五】注解编程

本文介绍了如何利用注解编程在Spring中替代XML配置,涵盖了基础注解如@Component、@Scope、@Lazy的使用,以及高级注解如@Configuration、@Bean、@ComponentScan的应用实例。还讲解了如何整合logback日志和Spring工厂创建对象的策略。
摘要由CSDN通过智能技术生成

注解编程

01 什么是注解编程

:::info
指的是在类或者方法上面加上特定的注解,完成特定功能的开发
使用注解开发方便,代码简洁,开发速度大大提供
:::

02 注解的作用

:::success
替换XML的这种配置形式,简化配置
:::

:::success
替换接口,实现双方 的契约型
:::

基础注解

01 注解扫描

在Spring的配置文件,加入组件扫描器的标签,说明注解在项目中的位置,让Spring扫描这些包,让他们生效

1、spring的配置文件,会扫描当前包及其子包

<context:component-scan base-package="包名"></context:component-scan>

2、扫描多个包的方式

  • 使用多次组件扫描器,指定不同的包
  • 使用分割符; 或者是 ,分割多个包名
  • 指定父包

1.1 排除方式

排除策略可以叠加使用

<context:component-scan base-package="包名">
	<context:exclude-filter type="类型" expression="表达式"/>
</context:component-scan>
  • annotation:排除特定的注解
    • org.springframework.stereotype.注解名:Service,Component等等
  • **aspectj**:切入点表达式,仅支持包切入点和类切入点
  • assignable:排除特定的类型
  • **regex**:正则表达式
  • **custom**:自定义排除策略,框架底层开发

1.2 包含方式

<!-- use-default-filters="false"  :  让Spring默认的注解扫描方式失效 -->
<context:component-scan base-package="包名" use-default-filters="false">
<!--指定扫描哪一个注解-->
	<context:include-filter type="" expression="包名"/>
</context:component-scan>

02 创建对象常用的注解

2.1 @Component

  • 作用:替换原来的Spring配置文件中的<bean> 标签
    • id属性:在@Component 标签中提供了默认的设置方式, 首字母小写
    • class属性:通过反射获得class的内容
  • 属性value就是对象的名称,相当于bean标签的id,value值是唯一的;如果说,不指定value属性,id值就是单词首字母小写,是由Spring提供的
  • Spring配置文件覆盖注解配置内容,注解和配置文件中,id值和class值要设置保持一致
  • 创建的对象在整个spring容器中只有一个
  • 当一个类不确定是什么功能的时候,使用Component注解

衍生注解
:::success
本质上这些衍生注解就是@Component,作用,细节,用法都是一致的

目的: 为了更准确的表示功能
:::

  • @Repository:持久层注解,但是Spring整合Mybatis的过程中,不会使用这个注解或者@Component注解
  • @Service:用在业务层类上面
  • @Controller:控制层注解

2.2 @Scope

  1. 控制简单对象的创建次数
  2. 如果说指定为 singleton ,就只会创建一次;这个值就是默认值
  3. 如果说指定为 prototype,就会创建多次
  4. XML中
<bean id="userService" class="com.spring.proxy.UserServiceImpl" scope="singleton | prototype"></bean>
  1. 注解
@Service
@Scope(value = "singleton")
public class UserServiceImpl implements UserService{}

2.3 @Lazy

  1. 作用:用来延迟创建单实例对象
    • 位置在类上面,前提是有@Component注解
  2. 一般来说,Spring会在创建工厂的时候,创建所有单实例对象
  3. 注意
    • 一旦使用了@Lazy注解之后,Spring会在使用这个对象的时候,进行对象的创建
  4. XML
<bean id="userService" class="com.spring.proxy.UserServiceImpl" lazy-init="true"></bean>
  1. 注解
@Service
@Lazy
public class UserServiceImpl implements UserService{}

2.4 生命周期相关的注解

:::danger
这两个注解并不是Spring提供的,是JSR520(JavaEE规范)提供的
:::
初始化方法:@PostConstruct

    @PostConstruct
    public void init(){
        System.out.println("User.init");
    }

销毁方法:@PreDestroy

    @PreDestroy
    public void destroy(){
        System.out.println("User.destroy");
    }

注意事项

  • 并不是Spring提供的注解,是JSR520提供的(JavaEE规范)

03 注入相关的注解

3.1 JDK 类型

**@Value**
:::info
用于JDK基本类型的赋值
:::

1. 设置 xxx.properties,配置相应的键的值

2. Spring的工厂读取这个配置文件  <context:property-placeholder location="配置文件的位置"/>

3. 属性赋值  @Value("${key}")

:::success

  • 不能应用于静态成员变量上,如果使用,获取的值为null
  • 不能注入集合类型,Spring有提供了新的配置形式。比如说YAML,YML
    :::


**@PropertySource **
:::info
1、用于替换Spring配置文件中的<context:property-placeholder location="配置文件的位置"/>标签
:::

1. 设置 xxx.properties

2. 在实体类上应用 @PropertySource("classpath:/xxx.properties")

3. 属性赋值 @Value("${key}")

3.2 用户自定义类型

**@Autowired **

  1. 用于引用类型的赋值,使用的是自动注入原理,支持byNamebyType
  2. 默认使用的是byType自动注入,注入对象的类型,必须与目标成员变量类型相同或者是其子类(实现类)
  3. 如果说要使用byName的方式
  • 在属性上面加入@Autowired
  • 在属性上面加入@Qualifier(value="bean的id"):表示使用指定名称的bean完成赋值
  1. 属性required
  • 是一个boolean类型的,默认就是true,表示引用赋值失败,程序报错,并终止执行
  • 如果是false,说如果引用类型赋值失败,程序正常执行,引用类型是null
  • 一般情况下使用true,能够尽早的排查程序中的错误
  1. 可以放置在对应成员变量的set方法之上,也可以直接将这个注解放置在成员变量之上
  2. 当放置在成员变量之上,通过反射直接对变量进行赋值,不会调用Set方法,这种方式比较推荐
  3. 当放置在set方法之上,会执行set方法

**@Resource **

  1. 来自JDK的注解,Spring中提供了对这个注解的支持
  2. @Resouce(name="") 基于名字进行注入, 等价于@Autowired@Qualifier 联合实现的效果
  3. 先使用byName自动注入,如果说byName赋值失败,就会使用byType

04 对于注解开发的思考

  1. Spring注解配置 和 配置文件配置是互通的
  2. 在程序员开发的类型上,可以加入对应的注解,进行对象的创建
  3. 应用其他程序员开发的类型时,还是需要使用配置文件进行配置

高级注解

:::success
Spring 3.X 以上
:::

01 配置Bean

@Configuration

  • 用于替换XML配置文件
  • @Configuration:类上加入这个注解,就成为了配置Bean;同样是@Component的衍生注解
  • 可以应用<context:component-scan>进行扫描,但是不推荐使用
  • 原有XML中的内容都可以通过配置Bean进行解决
  • 使用这个注解后,使用AnnotationConfigApplicationContext ,创建工厂,如果先让这个工厂读取xml配置文件,就在配置类上添加@ImportResource("配置文件的位置")注解
# 方式一: 指定配置bean的Class,可以指定多个工厂
	ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig.class,AppConfig1.class);
	
# 方式二: 指定配置bean所在的路径,工厂会扫描这个包,查找具有@Configuration注解的类型
	ApplicationContext ac = new AnnotationConfigApplicationContext("所在的包的路径");

02 logback日志的整合

:::danger
基于注解开发的时候,不能够集成Log4j
:::

2.1 引入依赖

   <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>slf4j-api</artifactId>
      <version>1.7.25</version>
    </dependency>

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>1.7.25</version>
      <exclusions>
        <exclusion>
          <groupId>org.slf4j</groupId>
          <artifactId>slf4j-log4j12</artifactId>
        </exclusion>
      </exclusions>
    </dependency>

    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-classic</artifactId>
      <version>1.2.3</version>
    </dependency>

    <dependency>
      <groupId>ch.qos.logback</groupId>
      <artifactId>logback-core</artifactId>
      <version>1.2.3</version>
    </dependency>

    <dependency>
      <groupId>org.logback-extensions</groupId>
      <artifactId>logback-ext-spring</artifactId>
      <version>0.1.4</version>
    </dependency>

    <dependency>
      <groupId>org.slf4j</groupId>
      <artifactId>jcl-over-slf4j</artifactId>
      <version>1.7.5</version>
    </dependency>

2.2 引入logback的配置文件

<?xml version="1.0" encoding="UTF-8" ?>
<configuration>
    <appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppender">
        <encoder>
            <pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{35} - %msg %n</pattern>
        </encoder>
    </appender>

    <root level="DEBUG">
        <appender-ref ref="STDOUT" />
    </root>
</configuration>

03 @Bean

@Bean 注解在配置bean中进行使用,等同于Xml配置文件中的 标签

3.1 对象的创建

:::success
@Bean(“id值”) -------如果说不指定这个id值,方法名就是id值
:::
对象的创建

  • 简单对象:直接能够通过new方式创建的对象
  • 复杂对象:不同直接通过new的方式创建的对象

简单对象

@Bean
public 创建对象的类型 原来bean中的id值(){
    // 方法体:创建对象
     return 创建好的对象;
}
@Configuration
public class MyApp {
    @Bean
    public User user(){
        return new User();
    }
}


复杂对象

@Bean
@Scope("singleton")//控制对象的创建次数
public Connection conn() {
    Connection conn = null;
    try {
        Class.forName("com.mysql.cj.jdbc.Driver");
        conn = DriverManager.getConnection(
            "jdbc:mysql://localhost:3306/chat?serverTimezone=UTC",
            "root",
            "123456");
    } catch (ClassNotFoundException | SQLException e) {
        e.printStackTrace();
    }
    return  conn;
}

3.2 类型注入

3.2.1 用户自定义类型注入
//  方式一
@Configuration
public class AppConfig {
    @Bean
    public UserDao userDao(){
        return new UserDaoImpl();
    }
    @Bean
    public UserService userService(UserDao userDao){
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);
        return userService;
    }
}
// 方式二
@Configuration
public class AppConfig {
    @Bean
    public User user(){
        return new User();
    }
    @Bean
    public UserMapper userMapper(){
        return new UserMapperImpl();
    }
    @Bean
    public UserService userService(){
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserMapper(userMapper());
        userService.save();
        return userService;
    }
}

3.2.2 JDK类型注入
@Configuration
@PropertySource("classpath:/init.properties")
public class AppConfig {
    @Value("${id}")
    private String id;
    @Value("${name}")
    private String name;
    @Bean
    public User user(){
        User user = new User();
        user.setId(id);
        user.setName(name);
        return user;
    }
}

3.3 控制对象的创建次数

@Bean
@Scope("singleton | prototype") 默认值为singleton

04 @ComponentScan

4.1 基础使用

  • 在配置bean中进行使用,等同于在XML配置文件中的<context:component-scan base-package="">标签
  • 目的:能够进行相关注解的扫描

4.2 排除策略的使用

  • 注解方式:
  • 排除特定的注解:type = FilterType.ANNOTATION, value={}
  • 排除特定的类型:type = FilterType.ASSIGNABLE_TYPE , value={}
  • 切入点表达式:type = FilterType.ASPECTJ, pattern=""
  • 正则表达式:type = FilterType.REGEX, pattern=""
  • 自定义排除策略:type = FilterType.CUSTOM, value=""
@Configuration
@ComponentScan(basePackages = "com.study",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Service.class})}
)
public class AppConfig {
}

4.3 包含策略的使用

@ComponentScan(basePackages = "com.frame",
                useDefaultFilters = false,
                includeFilters = {
                    @ComponentScan.Filter(type = FilterType.ANNOTATION,value = {Service.class})
                }               
)  

05 Spring工厂创建对象的多种配置方式

5.1 多种创建对象的方式


**方式一:@Component **

  • 主要用于程序员自己开发的类型

**方式二:@Bean **

  • 框架提供的类型,别的程序员提供的类型

方式三:xml配置文件

  • 与遗留系统整合的时候,在纯注解的开发过程中,基本不会使用

**方式四:@Import **

  • 创建单个对象,会在Spring框架底层进行使用

5.2 多种创建对象的优先级

  1. @Component 及其衍生注解 < @Bean < XML配置
  2. 优先级高的配置,会覆盖优先级低的注解;前提是id值相同
  3. 通过配置优先级,可以解决基于注解进行配置的耦合问题,如果说对一个类不满意,可以使用优先级高的进行覆盖

06 整合多个配置信息

6.1 为什么会有多个配置信息

:::info
拆分多个配置bean的开发,是一种模块化开发的形式,也体现了面向对象各司其职的设计思想
:::


6.2 多配置信息整合的方式

:::success
多个配置Bean
:::

  • 基于basePackages包扫描的方式
ApplicationContext ac = new AnnotationConfigApplicationContext("包名");
  • @Import在一个配置Bean中引入另一个配置Bean,相当于<import resource=""/>
// 选择AppConfig1 作为主配置文件
@Configuration
@Import(AppConfig.class)
public class AppConfig1 {
    @Bean
    public Student student(){
        return new Student();
    }
}
// 创建工厂
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig1.class);
  • 在工厂创建的时候,指定多个配置Bean的class对象
ApplicationContext ac = new AnnotationConfigApplicationContext(AppConfig1.class,AppConfig2.class);

:::success
跨配置进行注入:通过提供成员变量并且使用@Autowired进行注入
:::

在应用配置Bean的过程中,不管使用哪种方式进行配置信息的汇总,其操作方式都是通过成员变量加上@Autowired注解完成的

@Configuration
@Import(AppConfig2.class)
public class AppConfig1 {
    @Autowired
    private UserMapper userMapper;
    @Bean
    public UserService userService(){
        UserServiceImpl  userService = new UserServiceImpl();
        userService.setUserMapper(userMapper);
        return userService;
    }
}



@Configuration
public class AppConfig2 {
    @Bean
    public UserMapper userMapper(){
        return new UserMapperImpl();
    }
}

:::success
配置Bean与@Component相关注解的整合
:::

@Component
public class UserMapperImpl implements UserMapper{}


@Configuration
@Import(AppConfig2.class)
@ComponentScan("注解扫描的包")
public class AppConfig1 {}

:::success
配置Bean与Spring的XML配置文件的整合

  • 遗留系统的整合
  • 配置覆盖
    :::
public class UserDAOImpl implements UserDAO{
}
<bean id="userDAO" class="com.baizhiedu.injection.UserDAOImpl"/>

@Configuration
@ImportResource("applicationContext.xml")
public class AppConfig4 {
  
    @Autowired
    private UserDAO userDAO;

    @Bean
    public UserService userService() {
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDAO(userDAO);
        return userService;
    }
}

ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig1.class);

6.3 配置Bean的底层实现原理

Spring 在配置Bean中加入@Configuration注解之后,底层就会通过Cglib的代理方式,来进行对象相关的配置处理


四维一体的开发

:::info
Spring在开发一个功能的时候,有四种形式,虽然说开发方式不同,但是最终的效果是一样的
:::

  1. 基于schema:<context:property-placeholder location=""/>
  2. 基于特定功能注解:@PropertySource("")
  3. 基于原始的Bean标签:<bean id="" class=""></bean>
  4. 基于@Bean注解:@Bean
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

佩奇inging

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值