Java – Spring – 基于注解管理Bean
简介
Spring 在2.5版之后,提出了基于注解进行管理Spring,关于使用XML管理Bean可参考以下文章:
@Component
传统xml配置Bean
使用传统xml方式配置Bean,通常我们可以使用<bean>标签进行配置
<bean id="" // Bean 的ID
class="" // Bean 的全类名
name="" // Bean 的别名
abstract="true" // 是否为
autowire="byType" // 自动装配使用那种方式(以类型或ID)
scope="singleton" // 作用域(单例或原型)
lazy-init="true" // 是否延迟加载
factory-method="" // 静态工厂方法创建Bean
factory-bean="" // 实例工厂方法创建Bean
init-method="" // 实例工厂初始化方法
destroy-method="" // 实例工厂销毁方法
/>
使用注解配置Bean对比
通过【@Component】注解,便可以让JavaBean类,作为Spring管理的Bean,如下
@Component("PersonService")
// 定义延迟加载
@Lazy(true)
// 定义作用域
@Scope("singleton")
public class PersonServiceImpl implements PersonService {
// 定义 init-method 方法
@PostConstruct
public void init(){}
// 定义 destroy-method 方法
@PreDestroy
public void destory(){}
}
1.因为【@Component】注解直接写在类定义上面,相当于完成xml中的【class】定义
2.【@Component】注解中,传入一个默认值【value】则是自定义Bean的ID,与xml中的【id】定义相同。如果不传入默认值,则id将被定义为【类名首写字母小写】的类名,如“personServiceImpl”
@Component 衍生注解
由于JavaEE开发是分层的,为了每层Bean标识的注解语义化更加明确,@Component 又衍生出如下三个注解
@Repository
: 在Dao层类上使用
@Service
: 在Service层类上使用
@Controller
: 在Web层类上使用
属性数据注入
类中有各种成员变量,在很多时候我们都需要为成员变量赋值。Spring提供了3+1一种数据注入的方式
传统xml注入
<bean id="" class="">
<property name="" value=""></property>
<property name="" ref=""></property>
</bean>
value 用于注入普通数据
ref 用于注入引用类型数据
使用注解注入
// 使用在字段或方法上,用于注入普通数据
@Value("#{systemProperties.myProp}")
private String username;
-------------------------------------------
// 使用在字段或方法上,用于根据类型(byType)注入引用数据
@Autowired
private UserService userService;
-------------------------------------------
// 使用在字段或方法上,结合@Autowired,根据名称注入
@Qualifier
private UserService userService;
-------------------------------------------
// 结合@Autowired,强制根据名称注入相应的Bean
@Autowired
@Qualifier("userDao2")
private UserDao userDao;
-------------------------------------------
// 使用在字段或方法上,根据类型或名称进行注入
// 不指定名称时以类型注入,如果有名称,就根据名称注入
@Resource(name="userService2")
private UserService userService;
-------------------------------------------
@Value("${jdbc.username}")
public void setUsername(String username){
this.username = username;
}
-------------------------------------------
// @Autowried 扩展一:set方法名随意
// @Autowried 不以set方法为查找方法,可以使用任意方法,
// 但是会依据传入的类型或形参名进行注入数据
public void xxx(UserDao userDao){
this.userDao = userDao;
}
-------------------------------------------
// @Autowried 扩展二:传入Bean的List集合
// 当Spring中存在多个相同类型的Bean时,@Autowried 可同时传入
public void yyy(List<UserDao> userDaoList){
...会把Spring中的所有UserDao打包成List集合
}
1.注入除了可以定义在成员变量上,也可以定义在set方法上。
2.@Autowried 注入set 方法时,可随意定义方法名,它以传入参数的类型和名称作为查找依据。
3.@Autowried 可注入 List 的Bean集合,当Spring中存在多个相同类型时,可以传递相同类型的集合。
非自定义Bean配置
当我们需要获取第三方对象作为Bean时,我们无法往第三方类中添加@Component 之类的注解,这时需要使用第三方Bean配置方式,使用【@Bean()】进行定义
@Bean()
@Component
public class OtherBean {
// 如果 @Bean 定义了名称,则该第三方Bean的名称就为定义名
// 如果 @Bean 没有定义名称,则该第三方Bean的名称为方法名
@Bean("dataSource")
public DataSource dataSource(
// 形参内可以使用 @Value @Autowired @Qualifier 注入
@Value("${jdbc.Driver}") String driverClassName,
// 如果需要注入引用类型的数据,可以使用 @Autowired
@Autowired Ref RefProp,
// 如果需要强制使用名称定义注入的数据,可以添加 @Qualifier
@Autowired @Qualifier("RefProp2") Ref RefProp2,
// 在形参内,@Qualifier 可以省略 @Autowired 单独使用
@Qualifier("RefProp3") Ref RefProp3,
// 在形参内,如果该参数是引用类型的话,可以直接省略,Spring
// 会按照参数名查找并进行注入
Ref RefProp4
){
DruidDataSource dataSource = new DruidDataSource();
return dataSource;
}
基于注解的配置项
通过以上的章节,我们知道如何使用注解来代替xml文件配置Bean,但是上面的章节中,使用的注解配置,是基于xml中配置<component-scan>标签实现的,若要完全脱离xml配置文件,我们同样可以使用注解的方式进行配置。
基本概念
如果我们使用xml文件作为Spring配置Bean的方式,那么我们必须创建一个xml文件作为配置的载体。
那么对于注解而言,我们如果使用注解来作为Spring配置Bean的方式,那么我们也必须创建一个类作为配置的载体。
可以把配置类,看作一个xml文件看待。
@Configuration
@Configuration 注解是用来描述用注解来配置的配置类声明,当类中加上@Configuration后,Spring就会认为这是一个配置类,它和@Component 类注解的区别在于,@Component 表示这个类是一个Bean,而@Configuration表示的是一个类似于applicationContext.xml文件的存在。
@ComponentScan
@ComponentScan 相当于xml文件中的 <context:component-scan/>标签,可以想象,<context:component-scan/>标签配置在xml文件中
相对的,@ComponentScan 注解,就应该配置在带有 @Configuration 注解的类中。
@Configuration
//<context:component-scan base-package="cn.unsoft"/>
@ComponentScan(basePackages = {"cn.unsoft"})
public class SpringAnnoConfig { }
basePackages 表示需要扫描的包目录的注解Bean,传入一个字符串数组,如果只有一个时,可以省略【{}】号。
同时 【basePackages】 也可以省略不写。
@PropertySource
@PropertySource 对应xml文件中的 <context:property-placeholder location="classpath:"/>标签
用于导入properties配置文件。
@Configuration
//<context:property-placeholder location="classpath:"/>
@PropertySource({"classpath:jdbc.properties"})
public class SpringAnnoConfig { }
@Import
@Import 对应xml中的<import resource="classpath:"/>,用于加载其它xml配置文件
@Import 是用于导入外部的其它配置类。如果需要加载其它xml配置文件的话,使用@ImportResource()
@Configuration
//<import resource="classpath:"/>
@Import({OtherConfig.class})
public class SpringAnnoConfig { }
@Import 重点技术
Spring与Mybatis注解方式整合有个重要的技术点是 @Import,第三方框架与Spring整合xml方式很多是凭借自定义标签完成的,而第三方框架与Spring整合注解方式很多是靠 @Import 注解完成的
@Import 可以导入如下三种类:
1.普通的配置类
2.实现ImportSelector接口的类
可以通过创建一个普通类,实现ImportSelector接口,ImportSelector接口提供了selectImports方法,该方法需要返回一个数组类型的String
返回类型表示需要被加入进BeanDefinitionMap中并实例化成Bean的全类名数组,可以在此提供需要创建为Bean的类,这种类可以完全是一个普通类,也就是说不需要带有 @Component 等注解的类也可以实现为Bean类。
public class MyImportSelector implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"cn.unsoft.bean.xxx"};
}
}
3.实现ImportBeanDefinitionRegistrar接口的类
可以通过创建一个普通类,实现ImportBeanDefinitionRegistrar接口,ImportBeanDefinitionRegistrar接口提供了registerBeanDefinitions方法,该方法可以通过BeanDefinitionRegistry 对象注册BeanDefinition对象,也就是需要我们自己去创建BeanDefinition,会把我们创建的BeanDefinition对象添加到BeanDefinitionMap中进行实例化Bean
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
BeanDefinition b = new RootBeanDefinition();
b.setBeanClassName("");
registry.registerBeanDefinition("beanName",b);
}
}
@Primary
@Primary 注解用于标注相同类型的Bean优先被使用权,是Spring3.0后引入的,与@Component和@Bean一起使用,标注了的Bean优先级更高,则在通过类型获取Bean或通过@Autowrired根据类型进行注入时,会选月优先级更高的。
@Component("PersonService")
// 当存在多个相同类型的Bean时,使用类型注入时,标注了@Primary的Bean优先级更高
@Primary
public class PersonServiceImpl implements PersonService { }
@Profile
@Profile 注解的作用相当于xml文件中的环境切换标签
<beans profile="test">
在xml中配置 profile 后,在该<beans>的范围内,只有通过运行时使用 -Dspring.profiles.active=test 或使用代码设置当前运行环境 System.setProperty("spring.profiles.active","test")时,带有@Profile("test")的Bean类才会被执行。
@Component("PersonService")
// 当前的运行环境是 test 或 product 时,这个类才会被加载到Spring Bean中
@Profile({"test","product"})
public class PersonServiceImpl implements PersonService { }
通过注解整合第三方技术
整合Druid和Mybatis
在使用注解整合Druid和Mybatis技术之前,我们可以看一下通过xml方式整合的方式:
<!--配置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="url" value="jdbc:mysq1://localhost:3306/mybatis"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<!--配置SqlSessionFactoryBean-->
<bean class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
</bean>
<!--配置Mapper包扫描-->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<property name="basePackage" value="com.itheima.dao"></property>
</bean>
实际上我们通过注解整合第三方技术,也只是通过xml的方式转化为一个类的方式:
@Configuration
@ComponentScan("cn.unsoft")
@PropertySource({"classpath:jdbc.properties"})
@MapperScan(basePackages = {"cn.unsoft.mapper"})
public class SpringAnnoConfig {
/**
* 使用注解配置 DataSource
* 配置信息通过 @PropertySource 读取配置文件
* 然后就可以通过 @Value 读取配置文件中的信息
* @param driver
* @param url
* @param username
* @param password
* @return
*/
@Bean
public DataSource dataSource(
@Value("${jdbc.driver}") String driver,
@Value("${jdbc.url}") String url,
@Value("${jdbc.username}") String username,
@Value("${jdbc.password}") String password
){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
/**
* 使用注解配置 Mybatis Bean 并使用 DataSource
* DataSource 通过上面的 DruidDataSource 创建
* 在接收参数里,DataSource 本应该需要使用 @Autowired 进行装配的
* 但是因为 DataSource 是引用类型,
* 引用类型 Spring 会通过形参名进行搜索Bean并自动装配
* 因此引用类型可以省略 @Autowired 注解
* @param dataSource
* @return
*/
@Bean
public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
sqlSessionFactoryBean.setDataSource(dataSource);
return sqlSessionFactoryBean;
}
/**
* 配置Mapper扫描
* 配置Mapper扫描是Mybatis用于扫描那些包中有Mybatis的Mapper接口
* 但是Mybatis提供了对应的扫描注解,因此不需要配置@Bean
* 可查看本类类名上的 @MapperScan 注解
*/
}
共有 0 条评论