Spring核心容器(四) | 注解开发 - bean管理 - 依赖注入 - 第三方bean管理
文章目录
注解开发
注解开发定义bean
快速入门
注解开发定义bean分两个步骤:
使用@Component定义bean, 默认的value就是指定bean的名称, 可以理解为配置中的id属性
@Component("bookDao")
public class BookDaoImpl implements BookDao {public void save() {System.out.println("Book Dao...");}
}
核心配置文件applicationContext.xml中, 通过组件扫描加载bean
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsd"><!--开启context命名空间, 扫描com.chenyq包下所有的类--><context:component-scan base-package="com.chenyq"/>
</beans>
使用@Component我们也可以不配置名称, 根据类型获取
@Component
public class BookDaoImpl implements BookDao {public void save() {System.out.println("Book Dao...");}
}
类型获取
public class App {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");BookDao bookDao = ctx.getBean(BookDao.class);bookDao.save();}
}
Spring提供@Component注解的三个衍生注解, 它们的使用方式和@Component完全一样
@Controller:用于表现层bean定义
@Service:用于业务层bean定义
@Repository:用于数据层bean定义
@Repository
public class BookDaoImpl implements BookDao {public void save() {System.out.println("Book Dao...");}
}
@Service("bookService")
public class BookServiceImpl implements BookService {public void save() {System.out.println("Book Service...");}
}
纯注解开发
Spring3.0升级了纯注解开发模式,使用Java类替代配置文件,开启了Spring快速开发赛道
Java类代替Spring核心配置文件, @Configuration注解用于设定当前类为配置类
// 表示当前类为配置类
@Configuration
public class SpringConfig {
}
@ComponentScan注解用于设定扫描的路径
@Configuration
@ComponentScan("com.chenyq")
public class SpringConfig {
}
@ComponentScan此注解只能添加一次,多个数据请用数组格式
@Configuration
@ComponentScan({"com.chenyq.dao", "com.chenyq.service"})
public class SpringConfig {
}
读取Spring核心配置文件初始化容器对象切换为读取Java配置类初始化容器对象
// 加载配置文件初始化容器
// ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
// 加载配置类的初始化容器
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
bean管理
bean作用范围
使用@Scope定义bean作用范围
我们知道bean默认情况下是单例模式, 有些特殊场景我们确确实实的希望bean是非单例模式的; 这个时候我们就可以通过@Score注解定义bean的作用范围, 也就是设置为非单例模式
@Repository
@Scope("prototype")
public class BookDaoImpl implements BookDao {public void save() {System.out.println("Book Dao...");}
}
bean生命周期
使用@PostConstruct、@PreDestroy定义bean生命周期
使用@PostConstruct注解定义的方法, 表示bean初始化的生命周期
使用@PreDestroy定义的方法, 表示bean销毁之前的生命周期
@Repository
public class BookDaoImpl implements BookDao {public void save() {System.out.println("Book Dao...");}@PostConstruct// @PostConstruct注解的方法表示初始化生命周期public void init() {System.out.println("Book Dao init...");}@PreDestroy// @PreDestroy注解的方法表示销毁之前生命周期public void destroy() {System.out.println("Book Dao destroy...");}
}
依赖注入
自动装配
使用@Autowired注解开启自动装配模式(按类型)
使用@Autowired注解, 我们就不再需要setter方法或者构造器, @Autowired注解会按照类型给属性自动装配
@Service("bookService")
public class BookServiceImpl implements BookService {@Autowired// 按类型, 自动装配类型为BookDao的beanprivate BookDao bookDao;public void save() {System.out.println("Book Service...");bookDao.save();}
}
注意:自动装配基于反射设计创建对象并暴力反射对应属性为私有属性初始化数据,因此无需提供setter方法
注意:自动装配建议使用无参构造方法创建对象,如果不提供对应构造方法,请提供唯一的构造方法
但是按类型自动装配要求装配的类型(例如上面的BookDao类型)是唯一的, 如果不唯一怎么办呢?
如果不唯一可以按照名称装配(但是不推荐)
@Repository("bookDao")
// 定义bean名称为bookDao
public class BookDaoImpl implements BookDao {public void save() {System.out.println("Book Dao...");}
}
@Service("bookService")
public class BookServiceImpl implements BookService {@Autowired// 按名称, 自动装配名称为bookDao的beanprivate BookDao bookDao;public void save() {System.out.println("Book Service...");bookDao.save();}
}
如果bean类型不唯一, Spring推荐使用@Qualifier注解开启指定名称装配bean(Spring推荐方式)
- 注意:@Qualifier注解无法单独使用,必须配合@Autowired注解使用
@Service("bookService")
public class BookServiceImpl implements BookService {@Autowired@Qualifier("bookDao")// @Qualifier注解按指定名称, 装配beanprivate BookDao bookDao;public void save() {System.out.println("Book Service...");bookDao.save();}
}
使用@Value实现简单类型注入:
@Repository("bookDao")
public class BookDaoImpl implements BookDao {@Value("chenyq")private String name;@Value("18")private int age;public void save() {System.out.println("Book Dao..." + name + " " + age);}
}
加载properties
在配置类上, 使用@PropertySource注解加载properties文件
例如有下面这样一个配置文件: jdbc.properties
name=coderwhy
age=18
在配置类中使用注解加载properties文件
@Configuration
@ComponentScan("com.chenyq")
@PropertySource("jdbc.properties")
public class SpringConfig {
}
使用依赖注入时, 可以注入properties文件中的属性
@Repository("bookDao")
public class BookDaoImpl implements BookDao {// ${}获取properties文件中的属性@Value("${name}")private String name;@Value("${age}")private int age;public void save() {System.out.println("Book Dao..." + name + " " + age);}
}
注意:路径仅支持单一文件配置,多文件请使用数组格式配置,不允许使用通配符*
@Configuration
@ComponentScan("com.chenyq")
// 多文件使用数组格式
@PropertySource({"jdbc.properties", "jdbc2.properties"})
public class SpringConfig {
}
第三方bean管理
第三方Bean管理
我们使用bean管理第三方数据库连接池Driver进行演示
首先导入Driver依赖到pom.xml文件中
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.0</version>
</dependency>
在配置对象中定义一个方法获得要管理的对象
@Configuration
public class SpringConfig {// 定义方法获得要管理的对象public DataSource dataSource() {// 原始的手动编程DruidDataSource ds = new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql:///db1");ds.setUsername("root");ds.setPassword("123456789");return ds;}
}
添加@Bean注解, 表示当前返回值是一个bean
@Configuration
public class SpringConfig {@Beanpublic DataSource dataSource() {DruidDataSource ds = new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql:///db1");ds.setUsername("root");ds.setPassword("123456789");return ds;}
}
再通过getbean方法获取即可
public class App {public static void main(String[] args) {ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);DataSource dataSource = ctx.getBean(DataSource.class);}
}
如果有其他的第三方bean需要管理, 我们需要再添加其他方法管理; 如果要管理的bean非常多, 那么配置类中就要写非常多的方法
所以为了避免这种情况, 我们通常使用独立的配置类管理第三方bean, 将第三方bean管理抽取到一个独立的配置类中
public class JdbcConfig {@Beanpublic DataSource dataSource() {DruidDataSource ds = new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql:///db1");ds.setUsername("root");ds.setPassword("123456789");return ds;}
}
- 将独立的配置文件加载到核心配置中有下面两种方式(推荐使用导入式)
方式一: 扫描式(不推荐)
给独立的配置文件也添加@Configuration注解
@Configuration
public class JdbcConfig {@Beanpublic DataSource dataSource() {DruidDataSource ds = new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql:///db1");ds.setUsername("root");ds.setPassword("123456789");return ds;}
}
再在核心配置文件中使用@ComponentScan注解扫描配置类所在的包,加载对应的配置类信息
@Configuration
@ComponentScan("com.chenyq.config")
public class SpringConfig {
}
方式二: 导入式(推荐方式)
抽取到独立的配置文件中不用动
public class JdbcConfig {@Beanpublic DataSource dataSource() {DruidDataSource ds = new DruidDataSource();ds.setDriverClassName("com.mysql.jdbc.Driver");ds.setUrl("jdbc:mysql:///db1");ds.setUsername("root");ds.setPassword("123456789");return ds;}
}
在核心配置文件中使用@Import注解手动加入配置类到核心配置,此注解只能添加一次,多个数据请用数组格式
@Configuration
@Import(JdbcConfig.class)
public class SpringConfig {
}
第三方bean依赖注入
第三方bean简单类型依赖注入:
简单类型依赖注入比较粗暴, 没什么好说的看代码
public class JdbcConfig {@Value("com.mysql.jdbc.Driver")private String driver;@Value("jdbc:mysql:///db1")private String url;@Value("root")private String username;@Value("123456789")private String password;@Beanpublic DataSource dataSource() {DruidDataSource ds = new DruidDataSource();ds.setDriverClassName(driver);ds.setUrl(url);ds.setUsername(username);ds.setPassword(password);return ds;}
}
第三方bean引用类型依赖注入:
引用类型注入只需要为bean定义的方法上设置形参即可,容器会根据类型自动装配对象
public class JdbcConfig { @Bean// 方法中提供形参public DataSource dataSource(BookDao bookDao) {System.out.println(bookDao);DruidDataSource ds = new DruidDataSource();// ...return ds;}
}
注解开发总结
XML配置与注解配置比较
功能 | XML配置 | 注解 |
---|---|---|
定义bean | bean标签 id属性 class属性 |
@Component @Controller @Service @Repository @ComponentScan |
设置依赖注入 | setter注入(set方法) 引用/简单 构造器注入(构造方法) 引用/简单 自动装配 |
@Autowired @Qualifier @Value |
配置第三方bean | bean标签 静态工厂、实例工厂、FactoryBean |
@Bean |
作用范围 | scope属性 | @Scope |
生命周期 | 标准接口 init-method ldestroy-method |
@PostConstructor @PreDestroy |