SSM-Spring-IOC/DI注解开发

目录


IOC/DI注解开发

[1 注解开发定义bean](#1 注解开发定义bean)

[2 纯注解开发模式](#2 纯注解开发模式)

步骤

Bean的作用范围

Bean生命周期

[3 注解开发依赖注入](#3 注解开发依赖注入)

@Autowired

注解实现按照名称注入

简单数据类型注入

注解读取properties配置文件

[4 IOC/DI 注解开发管理第三方bean](#4 IOC/DI 注解开发管理第三方bean)

[4.1 步骤(以管理第三方数据源为例)](#4.1 步骤(以管理第三方数据源为例))

[4.2 如果要将配置类分类的话 如何让全部的配置类都被扫描加载到,并且创建对象在IOC容器中?](#4.2 如果要将配置类分类的话 如何让全部的配置类都被扫描加载到,并且创建对象在IOC容器中?)

[4.3 注解开发实现为第三方bean注入资源](#4.3 注解开发实现为第三方bean注入资源)

1-注入简单数据类型

2-注入引用数据类型

[5 总结](#5 总结)


IOC/DI注解开发

1 注解开发定义bean

(1)将配置文件中的<bean>标签删除掉

(2)在BookDaoImpl类上添加@Component注解

@Component注解不可以添加在接口上,因为接口是无法创建对象的。

XML与注解配置的对应关系:

(3) 配置Spring的注解包扫描

为了让Spring框架能够扫描到写在类上的注解,需要在配置文件上进行包扫描

复制代码
<?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">
    <context:component-scan base-package="com.itheima"/>
</beans>

component-scan:组件扫描 Spring将管理的bean视作自己的一个组件

base-package指定Spring框架扫描的包路径,它会扫描指定包及其子包中的所有类上的注解。

包路径越多如:com.itheima.dao.impl,扫描的范围越小速度越快

包路径越少如:com.itheima,扫描的范围越大速度越慢

一般扫描到项目的组织名称即Maven的groupId下如:com.itheima即可。

说明:

@Component注解如果不起名称,会有一个默认值就是当前类名首字母小写,所以也可以按照名称 获取,如

复制代码
BookService bookService = (BookService)ctx.getBean("bookServiceImpl");
System.out.println(bookService);

对于@Component注解,还衍生出了其他三个注解@Controller、@Service、@Repository

这三个注解和@Component注解的作用是一样的,方便后期在编写类的时候能很好的区分出这个类是属于表现层、业务层还是数据层的类。

2 纯注解开发模式

上面已经可以使用注解来配置bean,但是依然有用到配置文件,在配置文件中对包进行了扫描, Spring在3.0版已经支持纯注解开发,Spring3.0开启了纯注解开发模式,使用Java类替代配置文件

步骤:

(1)删除配置文件applicationContext.xml删除掉,使用类来替换。

(2)创建配置类 SpringConfig、在配置类上添加@Configuration注解,将其标识为一个配置类,替换applicationContext.xml

(3)在配置类上添加包扫描注解@ComponentScan替换-scan base-package=""/>

复制代码
@Configuration
@ComponentScan("com.itheima")
public class SpringConfig {
}

(4) 运行

复制代码
public class AppForAnnotation {
 
    public static void main(String[] args) {
        ApplicationContext ctx = new 
AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        System.out.println(bookDao);
        BookService bookService = ctx.getBean(BookService.class);
        System.out.println(bookService);
   }
}

说明:

@ComponentScan注解用于设定扫描路径,此注解只能添加一次,多个数据请用数组格式

复制代码
@ComponentScan({com.itheima.service","com.itheima.dao"})

读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象

复制代码
//加载配置文件初始化容器
ApplicationContext ctx = new 
ClassPathXmlApplicationContext("applicationContext.xml");
//加载配置类初始化容器
ApplicationContext ctx = new 
AnnotationConfigApplicationContext(SpringConfig.class);

ClassPathXmlApplicationContext是加载XML配置文件

AnnotationConfigApplicationContext是加载配置类

Bean的作用范围

要想将BookDaoImpl变成非单例,只需要在其类上添加@scope注解

Bean生命周期

复制代码
@Repository
public class BookDaoImpl implements BookDao {
    public void save() {
        System.out.println("book dao save ...");
   }
    @PostConstruct //在构造方法之后执行,替换 init-method
    public void init() {
        System.out.println("init ...");
   }
    @PreDestroy //在销毁方法之前执行,替换 destroy-method
    public void destroy() {
        System.out.println("destroy ...");
   }
}

要想看到两个方法执行,需要注意的是destroy只有在容器关闭的时候,才会执行,所以需要修改App的类

复制代码
public class App {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext ctx = new 
AnnotationConfigApplicationContext(SpringConfig.class);
        BookDao bookDao1 = ctx.getBean(BookDao.class);
        BookDao bookDao2 = ctx.getBean(BookDao.class);
        System.out.println(bookDao1);
        System.out.println(bookDao2);
        ctx.close(); //关闭容器
   }
}

注意:@PostConstruct和@PreDestroy注解如果找不到,需要导入下面的jar包

复制代码
<dependency>
  <groupId>javax.annotation</groupId>
  <artifactId>javax.annotation-api</artifactId>
  <version>1.3.2</version>
</dependency>

找不到的原因是,从JDK9以后jdk中的javax.annotation包被移除了,这两个注解刚好就在这个包 中。

3 注解开发依赖注入

@Autowired

在BookServiceImpl类中添加了BookDao的属性,并提供了setter方法,但是目前是没有提供配置注入BookDao的,所以bookDao对象为Nul

解决方法:在BookServiceImpl类的bookDao属性上添加@Autowired注解

注意: @Autowired可以写在属性上,也可也写在setter方法上,最简单的处理方式是写在属性上并将 setter方法删除掉

为什么setter方法可以删除呢?

自动装配基于反射设计创建对象并通过暴力反射为私有属性进行设值,普通反射只能获取public修饰的内容,暴力反射除了获取public修饰的内容还可以获取private修改的内容,所以此处无需提供setter方法。

注意:

@Autowired默认按照类型自动装配,如果IOC容器中同类的Bean找到多个,就按照变量名和 Bean的名称匹配

注解实现按照名称注入

@Qualifier

当根据类型在容器中找到多个bean,注入参数的属性名又和容器中bean的名称不一致,这个时候该如何解决,就需要使用到@Qualifier来指定注入哪个名称的bean对象。

复制代码
@Service
public class BookServiceImpl implements BookService {
    @Autowired
    @Qualifier("bookDao1")
    private BookDao bookDao;
    
    public void save() {
        System.out.println("book service save ...");
        bookDao.save();
   }
}

注意:@Qualifier不能独立使用,必须和@Autowired一起使用

简单数据类型注入

使用@Value注解,将值写入注解的参数中就行了

复制代码
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    @Value("itheima")
    private String name;
    public void save() {
        System.out.println("book dao save ..." + name);
   }
}

注解读取properties配置文件

@Value一般会被用在从properties配置文件中读取内容进行使用

(1)使用注解加载properties配置文件

在配置类上添加@PropertySource注解

复制代码
@Configuration
@ComponentScan("com.itheima")
@PropertySource("jdbc.properties")
public class SpringConfig {
}

(2) 使用@Value读取配置文件中的内容

复制代码
@Repository("bookDao")
public class BookDaoImpl implements BookDao {
    @Value("${name}")
    private String name;
    public void save() {
        System.out.println("book dao save ..." + name);
   }
}

注意:

如果读取的properties配置文件有多个,可以使用@PropertySource的属性来指定多个

复制代码
 第一种方式
 @PropertySource({"jdbc.properties","xxx.properties"})
 第二种方式
 @PropertySource({"classpath:jdbc.properties"})
 //@PropertySource注解属性中可以把classpath:加上,代表从当前项目的根路径找文件

4 IOC/DI 注解开发管理第三方bean

如果是第三方的类,这些类都是 在jar包中,我们没有办法在类上面添加注解,这时候,我们就可以用到注解@Bean

4.1 步骤(以管理第三方数据源为例)

1-添加一个配置类

2-导入对应数据源jar包

3-在配置类上添加一个方法、并在该方法上添加@Bean注解

该方法的返回值就是要创建的Bean对象类型

复制代码
@Configuration
public class SpringConfig {
 @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setUsername("root");
        ds.setPassword("root");
        return ds;
   }
}

不能使用DataSource ds = new DruidDataSource() 因为DataSource接口中没有对应的setter方法来设置属性。

如果有多个bean要被Spring管理,直接在配置类中多些几个方法,方法上添加@Bean注解即可。

4.2 如果要将配置类分类的话 如何让全部的配置类都被扫描加载到,并且创建对象在IOC容器中?

(1)在Spring的配置类上添加包扫描

复制代码
@Configuration
@ComponentScan("com.itheima.config")
public class SpringConfig {
 
}

这种方式虽然能够扫描到,但是不能很快的知晓都引入了哪些配置类,所有这种方式不推荐使用。

(2)使用@Import注解

这种方案可以不用加@Configuration注解,但是必须在Spring配置类上使用@Import注解手动引入 需要加载的配置类

复制代码
@Configuration
//@ComponentScan("com.itheima.config")
@Import({JdbcConfig.class})
public class SpringConfig {
 
}

注意:

@Import参数需要的是一个数组,可以引入多个配置类。

@Import注解在配置类中只能写一次。

4.3 注解开发实现为第三方bean注入资源

1-注入简单数据类型

使用@Value注解引入值

复制代码
public class JdbcConfig {
    @Value("com.mysql.jdbc.Driver")
    private String driver;
    @Value("jdbc:mysql://localhost:3306/spring_db")
    private String url;
    @Value("root")
    private String userName;
    @Value("password")
    private String password;
 @Bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
   }
}
2-注入引用数据类型

步骤1:在SpringConfig中扫描BookDao

扫描的目的是让Spring能管理到BookDao,也就是说要让IOC容器中有一个bookDao对象

复制代码
@Configuration
@ComponentScan("com.itheima.dao")
@Import({JdbcConfig.class})
public class SpringConfig {
}

步骤2:在JdbcConfig类的方法上添加参数

复制代码
@Bean
public DataSource dataSource(BookDao bookDao){
    System.out.println(bookDao);
    DruidDataSource ds = new DruidDataSource();
    ds.setDriverClassName(driver);
    ds.setUrl(url);
    ds.setUsername(userName);
    ds.setPassword(password);
    return ds;
}

引用类型注入只需要为bean定义方法设置形参即可,容器会根据类型自动装配对象。

5 总结

相关推荐
Rust研习社1 小时前
组合真的优于继承吗?为什么 Rust 和 Go 都拥抱组合舍弃继承?
后端·rust·编程语言
IT_陈寒1 小时前
JavaScript的闭包把我坑惨了,说好的内存会自动回收呢?
前端·人工智能·后端
CaffeinePro2 小时前
Pydantic深度使用:数据校验、枚举、ORM映射
后端·fastapi
Chenyiax3 小时前
从 Chat 到 Responses:OpenAI API 抽象为什么变了?
后端
MariaH3 小时前
Koa和Express的区别
后端
MariaH3 小时前
Koa框架的使用
后端
luckdewei4 小时前
那个用 passlib 做认证的新同事,上线第一天就把用户密码写进了日志
后端
ping某5 小时前
为什么 Nginx 明明监听了 80,转发后端时却用了 4xxxx 端口?
后端·nginx
JustHappy5 小时前
我汇总了身边朋友的经历才发现,其实第一份实习是最难找的......
前端·后端·面试
uhakadotcom5 小时前
在python 的 工程化架构中 ,什么是 薄包装器层?
后端·面试·github