Bean 管理指的是两个操作:
以下demo我以上传至 github,文中代码块比较零散:https://github.com/Jacks5320/Spring-Study
使用的注解:
@Component
:将当前类对象存入 Spring
容器中。
Bean
的 id
,默认值为 Bean
的名称(首字母小写)。@Controller
:一般用于表现层。@Service
:一般用于服务层。@Repository
:一般用于数据持久层。@Component
衍生的注解,其功能都是用于创建对象的,这是是 Spring 框架为我们提供明确的三层架构注解,使我们对三层结构更加清晰。Java类
public interface UserDao {
public void doIt();
}
@Repository(value = "dao1")
public class UserDaoImpl implements UserDao{
@Override
public void doIt() {
System.out.println("dao 方法调用了...");
}
}
开启扫描包配置,需要引入 context 名称空间
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.jk"/>
beans>
测试方法:
@Test
public void testObject(){
ApplicationContext context =
new ClassPathXmlApplicationContext("bean.xml");
UserDao dao1 = context.getBean("dao1", UserDao.class);
dao1.doIt();
System.out.println(dao1);
}
关于扫描包配置的过滤器补充:
<context:component-scan base-package="com.jk" use-default-filters="false">
<context:include-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
context:component-scan>
<context:component-scan base-package="com.jk">
<context:exclude-filter type="annotation"
expression="org.springframework.stereotype.Controller"/>
context:component-scan>
使用的注解:
@Autowired
:自动按照类型注入,使用注解注入后,set 方法便不再是必须的了。@Qualifier
:按照名称(id)注入。注入 Bean 对象时,要与 @Autowired
注解一同使用。@Resource
:按照 bean 的 id 注入,可以单独使用,但不是 Spring 提供的注解。以上3个注解只能注入其他类型的 bean,不能注入基本类型和 String 类型,集合只能使用基于 xml 的方式注入。
@Value
:用于注入基本类型和 String 类型。可以使用 Spring 中的 SpEl
(Spring 的 EL 表达式),写法:${表达式}
dao接口和其实现类
public interface UserDao {
public void doIt();
}
@Repository(value = "dao1")
public class UserDaoImpl implements UserDao{
@Override
public void doIt() {
System.out.println("dao 方法调用了...");
}
}
service 类
@Service
public class UserService {
@Autowired
private UserDao ud;
public void run(){
System.out.println("service方法执行了...");
ud.doIt();
System.out.println("普通属性注入了" + this.name);
}
}
测试方法
@Test
public void testService(){
ApplicationContext context =
new ClassPathXmlApplicationContext("com/jk/f_annotations/bean.xml");
UserService us = context.getBean("userService", UserService.class);
System.out.println(us);
us.run();
}
当 UserDao 的实现类有多个时,如下:
@Repository(value = "dao1")
public class UserDaoImpl implements UserDao{
@Override
public void doIt() {
System.out.println("dao 方法调用了...");
}
}
@Repository(value = "dao2")
public class UserDaoImpl2 implements UserDao{
@Override
public void doIt() {
System.out.println("dao2 方法调用了...");
}
}
这时再运行刚才的方法,Spring 就会产生混淆,不知道该注入哪个实现类,有两种解决方案,如下所示:
//方案一:将变量名改成要注入实现类对应的 id 名
@Autowired
private UserDao dao2;
public void run() {
dao2.doIt();
}
//方案二:不改变变量名,配合 @Qualifier 确定唯一匹配对象。
@Autowired
@Qualifier("dao2")
private UserDao dao;
public void run() {
dao.doIt();
}
除了上述以外的注解,也可以使用 Java 自身提供的注解:javax.annotation.Resource:@Resource 进行注入。
@Resource(name = "dao1")
private UserDao dao;
以上注解都只能注入 Bean 类型的属性,如果要注入普通属性,则使用 @Value
注解,如下所示:
@Value("小明")
private String name;
@Value("12")
private int age;
public void run() {
System.out.println(this.name + "注入成功了。。");
System.out.println("年龄:" + this.age);
}
使用的注解:@Scope
作用:用于指定 bean 的作用范围
属性:value,指定范围的取值,固定值:singleton、prototype(单例、多例)
Java 类
@Component
@Scope(value = "prototype")
public class ScopeDemo {
}
测试方法:
@Test
public void testScope() {
ApplicationContext context =
new ClassPathXmlApplicationContext("com/jk/f_annotations/bean.xml");
ScopeDemo s1 = context.getBean("scopeDemo", ScopeDemo.class);
ScopeDemo s2 = context.getBean("scopeDemo", ScopeDemo.class);
System.out.println(s1 == s2);
}
使用到的注解:
@PreDestroy
:指定销毁方法@PostConstruct
:用于指定初始化方法javax.annotation.PostConstruct
、javax.annotation.PreDestroy
@Component
public class BeanLife {
String 变量 = "小明";
public BeanLife() {
System.out.println(变量 + "对象创建了。。。");
}
@PostConstruct
public void init(){
System.out.println(变量 +"初始化方法执行了。。。");
}
@PreDestroy
public void destroy(){
System.out.println(变量 + "对象销毁了。。。");
}
}
测试方法:
@Test
public void testLife() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("com/jk/f_annotations/bean.xml");
BeanLife b = context.getBean("beanLife", BeanLife.class);
System.out.println(b);
context.close();
}
@Scope("prototype")
注解来标注到 BeanLife
类上进行多例对象生命周期验证。使用注解配置类时,就可以不配置 xml 文件了,可以实现完全注解开发。
使用到的注解:
@Configuration
:标注当前类是一个配置类,可以替代 xml 文件,当配置类作为 AnnotationConfigApplicationContext
对象创建的参数时,该注解可以省略。@ComponentScan
:指定 Spring 创建容器时要扫描的包
@Bean
:用于把当前方法的返回值存入 Spring IoC 容器中。
@Import
:用于把其他的配置类导入到主配置类
@PropertySource
:用于指定 properties 文件的位置
classpath:
表示类路径@Qualifier
@Autowire
一起使用使用到的注解:@Configuration
和 @ComponentScan
使用到的实现类:AnnotationConfigApplicationContext
定义配置类
@Configuration//把当前类作为配置类,用于替代 xml 配置文件
@ComponentScan(basePackages = {"com.jk"}) //包扫描
public class SpringConfig {
}
@Configuration
注解标注类@ComponentScan
标注扫描包,可以有多个路径,用逗号隔开。加载配置类
// 加载配置类
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
ApplicationContext
接口的另一个实现类:AnnotationConfigApplicationContext
,参数是配置类的字节码文件,是可变长参数。AnnotationConfigApplicationContext
的参数传入,就可以省略 @Configuration
注解。使用到的注解:@import
,导入其他配置类,参数为其他配置类的字节码文件。
子配置类
public class JdbcConfig {}
主配置类
@Configuration//把当前类作为配置类,用于替代 xml 配置文件
@ComponentScan(basePackages = {"com.jk.f_annotations.demo3"}) //包扫描
@Import(JdbcConfig.class)
public class SpringConfig {
}
@import
注解可以将子配置类导入父配置类中。AnnotationConfigApplicationContext
实现类中,这样就变成兄弟配置类了。
AnnotationConfigApplicationContext(SpringConfig.class, JdbcConfig.class)
@Configuration
注解标注,也能成功读取配置文件。使用的注解:@Bean
,将标注方法返回的对象放入 Spring IoC 容器中管理。
Java 类
public class JdbcConfig {
@Bean("jt")
@Scope("prototype")
public JdbcTemplate createJt(DataSource dataSource){
return new JdbcTemplate(dataSource);
}
/**
* 创建数据源对象
*
*/
@Bean("dataSource")
public DruidDataSource createDataSource(){
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
ds.setUrl("jdbc:mysql://localhost:3306/example?serverTimezone=Asia/Shanghai");
ds.setUsername("root");
ds.setPassword("root");
return ds;
}
}
@Bean
标注的方法会将返回值存入 Spring IoC 容器,默认 id 是方法名。使用到的注解:
@PropertySource
,用于指定 properties 配置文件的位置。标注在类上。@Value
,借助 SpEl 表达式读取配置文件的信息,并注入到属性中。jdbc.properties配置文件
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/example?serverTimezone=Asia/Shanghai
jdbc.username=root
jdbc.password=root
@Configuration
@PropertySource("classpath:com/jk/f_annotations/demo3/config/jdbc.properties")
public class JdbcConfig {
// jdbc连接信息
@Value("${jdbc.driver}")
String driver;
@Value("${jdbc.url}")
String url;
@Value("${jdbc.username}")
String username;
@Value("${jdbc.password}")
String password;
// 创建数据源对象
@Bean("dataSource")
public DruidDataSource createDataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
// 创建 JdbcTemplate 对象
@Bean("jt")
@Scope("prototype")
public JdbcTemplate createJt(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
使用的注解:@Qualifier
用于按名称注入 Bean 类型的参数。
package com.jk.f_annotations.demo3.config;
import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.*;
import org.springframework.jdbc.core.JdbcTemplate;
import javax.sql.DataSource;
/**
* Bean 注解
* 作用:把当前对象的返回值存入 Spring IoC容器
* 属性:name,用于指定 Bean 的 id,默认值为当前方法的名称。
* 细节:当使用注解配置方法时,如果方法有参数,Spring框架回去容器中查找有没有可用的 Bean对象。
* 查找方式与 @Autowired 一样。
*/
@Configuration
@PropertySource("classpath:com/jk/f_annotations/demo3/config/jdbc.properties")
public class JdbcConfig {
//jdbc连接信息
@Value("${jdbc.driver}")
String driver;
@Value("${jdbc.url}")
String url;
@Value("${jdbc.username}")
String username;
@Value("${jdbc.password}")
String password;
@Bean("dataSource")
public DruidDataSource createDataSource() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword(password);
return ds;
}
@Bean("dataSource2")
public DruidDataSource createDataSource2() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(driver);
ds.setUrl(url);
ds.setUsername(username);
ds.setPassword("");
return ds;
}
/**
* 创建 JdbcTemplate 对象
*/
@Bean("jt")
@Scope("prototype")
public JdbcTemplate createJt(@Qualifier("dataSource") DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
}
@Qualifier
的好处是,方便切换数据源。Spring IoC 基于注解的方式管理 Bean 就到此为止了。