文章目录
Bean基本注解开发
基本Bean注解,主要是使用注解的方式替代原有xml的 <bean> 标签及其标签属性的配置
<bean id="" name="" class="" scope="" lazy-init="" init-method="" destroy-method="" abstract="" autowire="" factory-bean="" factory-method=""></bean>
xml配置 | 注解 | 描述 |
---|---|---|
<bean id=“” class=“”> | @Component | 被该注解标识的类,会在指定扫描范围内被Spring加载并实例化 |
@Component
可以通过@Component注解的value属性指定当前Bean实例的beanName,也可以省略不写,不写的情况下为当前类名首字母小写
//获取方式:applicationContext.getBean("userDao");
@Component("userDao")
public class UserDaoImpl implements UserDao {
}
//获取方式:applicationContext.getBean("userDaoImpl");
@Component
public class UserDaoImpl implements UserDao {
}
使用注解对需要被Spring实例化的Bean进行标注,但是需要告诉Spring去哪找这些Bean,要配置组件扫描路径
<?xml version="1.0" encoding="UTF-8"?>
<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 https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 告知Spring框架去rqz包及其子包下去扫描使用了注解的类 -->
<context:component-scan base-package="com.rqz"/>
</beans>
其他属性注解配置
xml配置<bean>时其他属性注解配置
<bean id="" name="" class="" scope="" lazy-init="" init-method="" destroy-method="" abstract="" autowire="" factory-bean="" factory-method=""></bean>
xml配置 | 注解 | 描述 |
---|---|---|
<bean scope=“”> | @Scope | 在类上或使用了@Bean标注的方法上,标注Bean的作用范围,取值为singleton或prototype |
<bean lazy-init=“”> | @Lazy | 在类上或使用了@Bean标注的方法上,标注Bean是否延迟加载,取值为true和false |
<bean init-method=“”> | @PostConstruct | 在方法上使用,标注Bean的实例化后执行的方法 |
<bean destroy-method=“”> | @PreDestroy | 在方法上使用,标注Bean的销毁前执行方法 |
使用上述注解完成UserDaoImpl的基本配置
@Component("userDao")
@Scope("singleton")
@Lazy(true)
public class UserDaoImpl implements UserDao{
@PostConstruct
public void init(){}
@PreDestroy
public void destroy(){}
}
由于JavaEE开发是分层的,为了每层Bean标识的注解语义化更加明确,@Component又衍生出如下三个注解:
@Component衍生注解 | 描述 |
---|---|
@Repository | 在Dao层类上使用 |
@Service | 在Service层类上使用 |
@Controller | 在Web层类上使用 |
@Repository("userDao")
public class UserDaoImpl implements UserDao{}
@Service("userService")
public class UserServiceImpl implements UserService{}
@Controller("userController")
public class UserController {}
Bean依赖注入注解开发
Bean依赖注入的注解,主要是使用注解的方式替代xml的 <property> 标签完成属性的注入操作
<bean id="" class="">
<property name="" value=""/>
<property name="" ref=""/>
</bean>
Spring主要提供如下注解,用于在Bean内部进行属性注入的:
属性注入注解 | 描述 |
---|---|
@Value | 使用在字段或方法上,用于注入普通数据 |
@Autowired | 使用在字段或方法上,用于根据类型(byType)注入引用数据 |
@Qualifier | 使用在字段或方法上,结合@Autowired,根据名称注入 |
@Resource | 使用在字段或方法上,根据类型或名称进行注入 |
@Value
通过@Value 直接注入普通属性
@Value("rqz")
private String username;
@Value("rqz")
public void setUsername(String username){
System.out.println(username);
}
通过@Value 注入properties文件中的属性
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.username}")
public void setUsername(String username){
System.out.println(username);
}
加载properties文件
<context:property-placeholder location="classpath:jdbc.properties"/>
@Autowired
@Autowired注解,用于根据类型进行注入,当容器中同一类型的Bean实例有多个时,会尝试自动根据名字进行二次匹配
//使用在属性上直接注入
@Autowired
private UserDao userDao;
//使用在方法上直接注入
@Autowired
public void setUserDao(UserDao userDao){
System.out.println(userDao);
}
//使用在方法上通过属性类型直接注入
@Autowired
public void show(UserDao userDao){
System.out.println(userDao);
}
//使用在方法上通过属性类型将所有BeanFactory内的UserDao直接注入进List
@Autowired
public void show(List<UserDao> userDaoList){
System.out.println(userDaoList);
}
@Qualifier
@Qualifier配合@Autowired可以完成根据名称注入Bean实例,使用@Qualifier指定名称
@Autowired
@Qualifier("userDao")
private UserDao userDao;
@Autowired
@Qualifier("userDao")
public void setUserDao(UserDao userDao){
System.out.println(userDao);
}
@Resource
@Resource注解既可以根据类型注入,也可以根据名称注入,无参就是根据类型注入,有参数就是根据名称注入
@Resource
private UserDao userDao;
@Resource(name = "userDao2")
public void setUserDao(UserDao userDao){
System.out.println(userDao);
}
@Resource注解存在与 javax.annotation 包中,Spring对其进行了解析
非自定义Bean注解开发
非自定义Bean不能像自定义Bean一样使用@Component进行管理,非自定义Bean要通过工厂的方式进行实例化,使用@Bean标注方法即可,@Bean的属性为beanName,如不指定beanName,则使用当前方法名称存入BeanFactory
//将方法返回值Bean实例以@Bean注解指定的名称存储到Spring容器中
@Bean("dataSource")
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName("com.mysql.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://localhost:3306/mybatis");
dataSource.setUsername("root");
dataSource.setPassword("root");
return dataSource;
}
工厂方法所在类必须要被Spring管理
如果@Bean工厂方法需要参数的话,则有如下几种注入方式:
- 使用@Autowired 根据类型自动进行Bean的匹配,@Autowired可以省略;
- 使用@Qualifier 根据名称进行Bean的匹配;
- 使用@Value 根据名称进行普通数据类型匹配。
@Bean
@Autowired //根据类型匹配参数,可以省略
public Object objectDemo01(UserDao userDao){
System.out.println(userDao);
return new Object();
}
@Bean
public Object objectDemo02(@Qualifier("userDao") UserDao userDao, @Value("${jdbc.username}") String username){
System.out.println(userDao);
System.out.println(username);
return new Object();
}
Bean配置类的注解开发
@Component等注解替代了<bean>标签,但是像<import>、<context:componentScan> 等非<bean> 标签怎样去使用注解替代呢?
<!-- 加载properties文件 -->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 组件扫描 -->
<context:component-scan base-package="com.rqz"/>
<!-- 引入其他xml文件 -->
<import resource="classpath:beans.xml"/>
定义一个配置类替代原有的xml配置文件,<bean>标签以外的标签,一般都是在配置类上使用注解完成的
@Configuration
@Configuration注解标识的类为配置类,替代原有xml配置文件,该注解第一个作用是标识该类是一个配置类,第二个作用是具备@Component作用
@Configuration
public class ApplicationContextConfig {}
@ComponentScan
@ComponentScan 组件扫描配置,替代原有xml文件中的<context:component-scan base-package=“”/>
@Configuration
@ComponentScan({"com.rqz.service","com.rqz.dao"})
public class ApplicationContextConfig {}
base-package的配置方式:
- 指定一个或多个包名:扫描指定包及其子包下使用注解的类
- 不配置包名:扫描当前@componentScan注解配置类所在包及其子包下的类
@PropertySource
@PropertySource 注解用于加载外部properties资源配置,替代原有xml中的 <context:property-placeholder location=“”/> 配置
@Configuration
@ComponentScan
@PropertySource({"classpath:jdbc.properties","classpath:xxx.properties"})
public class ApplicationContextConfig {}
@Import
@Import 用于加载其他配置类,替代原有xml中的<import resource=“classpath:beans.xml”/>配置
@Configuration
@ComponentScan
@PropertySource("classpath:jdbc.properties")
@Import(OtherConfig.class)
public class ApplicationContextConfig {}
Spring 配置其他注解
@Primary
@Primary注解用于标注相同类型的Bean优先被使用权,@Primary 是Spring3.0引入的,与@Component和@Bean一起使用,标注该Bean的优先级更高,则在通过类型获取Bean或通过@Autowired根据类型进行注入时,会选用优先级更高的
@Repository("userDao")
public class UserDaoImpl implements UserDao{}
@Repository("userDao2")
@Primary
public class UserDaoImpl2 implements UserDao{}
@Bean
public UserDao userDao01(){return new UserDaoImpl();}
@Bean
@Primary
public UserDao userDao02(){return new UserDaoImpl2();}
@Profile
@Profile 注解的作用同于xml配置时学习profile属性,是进行环境切换使用的
<beans profile="test">
注解 @Profile 标注在类或方法上,标注当前产生的Bean从属于哪个环境,只有激活了当前环境,被标注的Bean才能被注册到Spring容器里,不指定环境的Bean,任何环境下都能注册到Spring容器里
@Repository("userDao")
@Profile("test")
public class UserDaoImpl implements UserDao{}
@Repository("userDao2")
public class UserDaoImpl2 implements UserDao{}
可以使用以下两种方式指定被激活的环境:
- 使用命令行动态参数,虚拟机参数位置加载 -Dspring.profiles.active=test
- 使用代码的方式设置环境变量 System.setProperty(“spring.profiles.active”,“test”);
Spring注解的解析原理
xml方式配置组件扫描
使用xml方式配置组件扫描,而component-scan是一个context命名空间下的自定义标签,所以要找到对应的命名空间处理器NamespaceHandler 和 解析器,查看spring-context包下的spring.handlers文件
http\://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
查看 ContextNamespaceHandler 类
public void init() {
this.registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
}
将ComponentScanBeanDefinitionParser进行了注册,对其源码进行跟踪,最终将标注的@Component的类,生成对应的BeanDefiition放进BeanDefiitionMap进行了注册
注解方式配置组件扫描
使用配置类配置组件扫描,使用AnnotationConfigApplicationContext容器在进行创建时,内部调用了如下代码,该工具注册了几个Bean后处理器:
AnnotationConfigUtils.registerAnnotationConfigProcessors(this.registry);
其中,ConfigurationClassPostProcessor 是一个 BeanDefinitionRegistryPostProcessor,经过一系列源码调用,最终也别指定到了ClassPathBeanDefinitionScanner 的doScan 方法(与xml方式最终终点一致)
区别
xml方式:在自定义命名空间中的ComponentScanBeanDefinitionParser中进行解析,最后调用doScan方法将beanDefinition放进beanDefinitionMap。
注解方式:通过ConfigurationClassPostProcessor方法内部调用doScan方法将beanDefinition放进beanDefinitionMap。