spring-ioc基础学习(3)基于JavaConfig的配置
使用JavaConfig配置,替代原本spring的xml配置
主要目标
- 学习JavaConfig替代spring的xml配置
- 熟悉相关的注解配置
JavaConfig的引入
spring从3.0版本引入JavaConfig提供配置功能,就可以使用JavaConfig替代xml文件进行配置,从4.0开始支持springboot后,springboot完全采用JavaConfig的方式进行开发配置
JavaConfig的使用
1)构建spring项目
- 建立maven项目
- pom.xml文件中引入所需jar包
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.21</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
</dependencies>
- 建立JavaConfig配置类,使用@Configuration进行标注后被java自动识别为JavaConfig类
@Configuration
public class IocJavaConfig {}
- 4.建立测试使用的接口和类
com.learn.controller
UserController
com.learn.service
IBeanService
com.learn.service.impl
UserServiceImpl
com.learn.dao
IBeanDao
com.learn.dao.impl
UserDaoImpl
com.learn.bean
User
Role
- 建立外部配置文件
mysql.username=mall
mysql.password=mall
mysql.url=jdbc:mysql://192.168.1.150:3306/mall
mysql.driver=com.mysql.jdbc.Driver
2)进行类的装载配置
- 1.装载外部类,使用@Bean注解进行装载注册
/**
*@Bean 将一个类的实例,注册到容器中成为一个容器中的bean被调用
* @return
*/
@Bean
public DruidDataSource druidDataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setName(Db.NAME);
dataSource.setPassword(Db.PASSWORD);
dataSource.setUrl(Db.URL);
dataSource.setDriverClassName(Db.DRIVER);
System.out.println("注册DruidDataSource");
return dataSource;
}
测试
/**
* 测试通过@Bean进行第三方类注入
*/
@Test
public void test01(){
DruidDataSource druidDataSource = context.getBean("druidDataSource",DruidDataSource.class);
DruidDataSource druidDataSource1 = context.getBean(DruidDataSource.class);
DruidDataSource druidDataSource2 = (DruidDataSource)context.getBean("druidDataSource");
System.out.println(druidDataSource);
}
- 2.装载配置属性文件,使用@PropertySource标签将属性文件装载,并使用${}方式读取属性文件
@Configuration
@PropertySource("classpath:db.properties")
public class IocJavaConfig{
private static class Db{
@Value("${mysql.name}")
private static String NAME;
@Value("${mysql.password}")
private static String PASSWORD;
@Value("${mysql.url}")
private static String URL;
@Value("${mysql.driver}")
private static String DRIVER;
}
}
- 3.包扫描方式添加注册类,@ComponentScan标签指定对应的包路径,会将包内标注了@Component组件标签的类装载到容器中
@Configuration
@ComponentScan({"com.learn.dao","com.learn.service","com.learn.controller"},
includeFilters={@ComponentScan.Filter(type=FilterType.ANNOTATION,value = {Controller.class, Service.class})},useDefaultFilters = false
)
@PropertySource("classpath:db.properties")
public class IocJavaConfig{}
@Service("userService")
public class UserServiceImpl implements IBeanService<User> {
public UserServiceImpl() {
System.out.println("创建UserServiceImpl");
}
@Autowired
IBeanDao<User> userDao;
@Override
public User insert(User user) {
return userDao.insert(user);
}
@Override
public boolean delete(Long id) {
return userDao.delete(id);
}
@Override
public User update(Long id, User user) {
return userDao.update(id, user);
}
@Override
public List<User> listAll() {
return userDao.listAll();
}
}
测试
/**
*测试通过@ComponentScan进行包扫描
*/
@Test
public void test02(){
IBeanService<User> userService = context.getBean(IBeanService.class);
userService.listAll();
userService = context.getBean("userService",IBeanService.class);
userService.listAll();
}
- 4.注册内部类
/**
* 内部bean的相互调用直接使用方法
* @Bean可以设置多个name别名用来进行获取bean实例
* @return
*/
@Bean(name={"userwx","wx"})
public User user(){
User user = new User();
user.setId(1L);
user.setName("wx");
user.setWife(wife());
return user;
}
@Bean
public Wife wife(){
Wife wife = new Wife();
wife.setId(2L);
wife.setName("bxl");
return wife;
}
测试
/**
* 测试内部bean的相互调用直接使用方法
*/
@Test
public void test03(){
User user = context.getBean("userwx",User.class);
User user2 = context.getBean(User.class);
System.out.println(user);
}
- 5.在@Bean中设置生命周期函数@Bean(initMethod = "methodName",destroyMethod = "methodName")
public class Wife extends Person{
public Wife() {
System.out.println("创建wife");
}
public void init(){
System.out.println("初始化wife");
}
public void destroy(){
System.out.println("注销wife");
}
}
@Bean(initMethod = "init",destroyMethod = "destroy")
public Wife wife(){
Wife wife = new Wife();
wife.setId(2L);
wife.setName("bxl");
return wife;
}
测试
/**
* 测试@Bean的生命周期
*/
@Test
public void test03(){
User user = context.getBean("userwx",User.class);
User user2 = context.getBean(User.class);
System.out.println(user);
}
- 指定bean的作用域@Scope标签
- 导入其他配置类或其他类使用@Import
就像在Spring XML文件中使用<import/>元素来帮助模块化配置一样;
@Import 注解允许从另一个配置类加载@Bean定义
@Configuration
@ComponentScan({"com.learn.dao","com.learn.service","com.learn.controller"})
@PropertySource("classpath:db.properties")
@Import(value = {AuxiliaryConfig.class, Role.class})
public class IocJavaConfig{}
@Configuration
public class AuxiliaryConfig {
@Bean(name = {"person","p"})
public Person person(){
Person person = new Person();
person.setId(3L);
person.setName("person");
return person;
}
}
public class Person {
private Long id;
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Person{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
public class Role {
public Role() {
System.out.println("实例化Role");
}
@Value("1")
private long id;
@Value("admin")
private String roleName;
@Override
public String toString() {
return new StringJoiner(", ", Role.class.getSimpleName() + "[", "]")
.add("id=" + id)
.add("roleName='" + roleName + "'")
.toString();
}
}
测试
/**
* 测试通过@Import进行类注入
*/
@Test
public void test04(){
Role role = context.getBean(Role.class);
System.out.println(role);
Person person = context.getBean("p",Person.class);
System.out.println(person);
}
注解解析
@Configuration
使用方式
使用在类、接口(包括注释类型)或枚举声明之上
作用
用作标识配置类,替换spring的xml配置文件,作用等价于<beans>标签,在其中可以进行的操作:
- 声明要注册的类 @Bean
- 导入其他配置文件 @Import
- 进行包扫描@ComponentScan等操作
源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
@AliasFor(annotation = Component.class)
String value() default "";
boolean proxyBeanMethods() default true;
}
@Bean
使用方式
使用在方法,声明类型上
作用
指示一个方法生成一个由Spring容器管理的bean,等价于spring的xml配置文件中的<bean>标签,用来将一个实例对象注入到容器中,可以进行的操作有:
- 设定类的生命周期 initMethod,destroyMethod
- 设置别名 name
源码
@Target({ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Bean {
@AliasFor("name")
String[] value() default {};
@AliasFor("value")
String[] name() default {};
@Deprecated
Autowire autowire() default Autowire.NO;
boolean autowireCandidate() default true;
String initMethod() default "";
String destroyMethod() default AbstractBeanDefinition.INFER_METHOD;
}
@Import
使用方式
使用在类、接口(包括注释类型)或枚举声明之上
作用
引入指定的类,可以引入多个,以及可以引入第三方包,用于将相关的类直接注册到容器中
源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
@ComponentScan
使用方式
使用在类、接口(包括注释类型)或枚举声明之上
作用
扫描定义的包路径,将包路径中进行使用@Component相关注解标注的文件,注册到容器中,可以设定扫描包中的加载方式是否为懒加载,设置过滤,扫描或不扫描某些类,配置
源码
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
Class<?>[] basePackageClasses() default {};
Class<? extends BeanNameGenerator> nameGenerator() default BeanNameGenerator.class;
Class<? extends ScopeMetadataResolver> scopeResolver() default AnnotationScopeMetadataResolver.class;
ScopedProxyMode scopedProxy() default ScopedProxyMode.DEFAULT;
String resourcePattern() default ClassPathScanningCandidateComponentProvider.DEFAULT_RESOURCE_PATTERN;
boolean useDefaultFilters() default true;
Filter[] includeFilters() default {};
Filter[] excludeFilters() default {};
boolean lazyInit() default false;
@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
@PropertySource
使用方式
使用在类、接口(包括注释类型)或枚举声明之上
作用
导入外部的配置文件
源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Repeatable(PropertySources.class)
public @interface PropertySource {
String name() default "";
String[] value();
boolean ignoreResourceNotFound() default false;
String encoding() default "";
Class<? extends PropertySourceFactory> factory() default PropertySourceFactory.class;
}
@Autowired
使用方式
使用在构造器,方法,形参,字段声明(包括枚举常量),注释声明之上
作用
自动注入,将容器中已有的bean注入到使用@Autowired标签的对象中,可以设定是否必须注入,默认为必须注入,如未能注入的情况下会产生报错
源码
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
boolean required() default true;
}
@DependsOn
使用方式
使用在类、接口(包括注释类型)或枚举声明之上,和方法之上
作用
进行注入bean的依赖设定,指定当前类依赖某个或某些类
源码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DependsOn {
String[] value() default {};
}
@Component/@Controller/@Service/@Repository
使用方式
使用在类、接口(包括注释类型)或枚举声明之上
作用
标注对应类要被注册到容器中,当被包扫描扫描后注入到容器中
源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
String value() default "";
}
@Scope
使用方式
使用在类,接口,或者枚举类上,也可以使用在方法上
作用
设定bean的作用域,默认为单例singleton,可选择为prototype原型模式,每次调用都有新的对象产生
源码
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
@AliasFor("scopeName")
String value() default "";
@AliasFor("value")
String scopeName() default "";
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
@Lazy
使用方式
使用在类,接口,或者枚举类上,也可以使用在方法上,属性,构造器,
作用
设置bean为懒加载,而不是启动容器后就加载
源码
@Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Lazy {
boolean value() default true;
}
@PostConstruct和@PreDestroy
使用方式
使用在方法之上
作用
将标注的方法设置为当前bean的初始化方法和销毁方法
源码
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}
@Value
使用方式
可以使用在属性,方法,参数,注释之上
作用
为标注属性设置值
源码
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
String value();
}