使用JavaConfig配置,替代原本spring的xml配置
主要目標(biāo)
- 學(xué)習(xí)JavaConfig替代spring的xml配置
- 熟悉相關(guān)的注解配置
JavaConfig的引入
spring從3.0版本引入JavaConfig提供配置功能,就可以使用JavaConfig替代xml文件進行配置,從4.0開始支持springboot后,springboot完全采用JavaConfig的方式進行開發(fā)配置
JavaConfig的使用
1)構(gòu)建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進行標(biāo)注后被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被調(diào)用
* @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標(biāo)簽將屬性文件裝載,并使用${}方式讀取屬性文件
@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標(biāo)簽指定對應(yīng)的包路徑,會將包內(nèi)標(biāo)注了@Component組件標(biāo)簽的類裝載到容器中
@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("創(chuàng)建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.注冊內(nèi)部類
/**
* 內(nèi)部bean的相互調(diào)用直接使用方法
* @Bean可以設(shè)置多個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;
}
測試
/**
* 測試內(nèi)部bean的相互調(diào)用直接使用方法
*/
@Test
public void test03(){
User user = context.getBean("userwx",User.class);
User user2 = context.getBean(User.class);
System.out.println(user);
}
- 5.在@Bean中設(shè)置生命周期函數(shù)@Bean(initMethod = "methodName",destroyMethod = "methodName")
public class Wife extends Person{
public Wife() {
System.out.println("創(chuàng)建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標(biāo)簽
- 導(dǎo)入其他配置類或其他類使用@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
使用方式
使用在類、接口(包括注釋類型)或枚舉聲明之上
作用
用作標(biāo)識配置類,替換spring的xml配置文件,作用等價于<beans>標(biāo)簽,在其中可以進行的操作:
- 聲明要注冊的類 @Bean
- 導(dǎo)入其他配置文件 @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>標(biāo)簽,用來將一個實例對象注入到容器中,可以進行的操作有:
- 設(shè)定類的生命周期 initMethod,destroyMethod
- 設(shè)置別名 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
使用方式
使用在類、接口(包括注釋類型)或枚舉聲明之上
作用
引入指定的類,可以引入多個,以及可以引入第三方包,用于將相關(guān)的類直接注冊到容器中
源碼
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
Class<?>[] value();
}
@ComponentScan
使用方式
使用在類、接口(包括注釋類型)或枚舉聲明之上
作用
掃描定義的包路徑,將包路徑中進行使用@Component相關(guān)注解標(biāo)注的文件,注冊到容器中,可以設(shè)定掃描包中的加載方式是否為懶加載,設(shè)置過濾,掃描或不掃描某些類,配置
源碼
@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
使用方式
使用在類、接口(包括注釋類型)或枚舉聲明之上
作用
導(dǎo)入外部的配置文件
源碼
@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
使用方式
使用在構(gòu)造器,方法,形參,字段聲明(包括枚舉常量),注釋聲明之上
作用
自動注入,將容器中已有的bean注入到使用@Autowired標(biāo)簽的對象中,可以設(shè)定是否必須注入,默認(rèn)為必須注入,如未能注入的情況下會產(chǎn)生報錯
源碼
@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的依賴設(shè)定,指定當(dāng)前類依賴某個或某些類
源碼
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DependsOn {
String[] value() default {};
}
@Component/@Controller/@Service/@Repository
使用方式
使用在類、接口(包括注釋類型)或枚舉聲明之上
作用
標(biāo)注對應(yīng)類要被注冊到容器中,當(dāng)被包掃描掃描后注入到容器中
源碼
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
String value() default "";
}
@Scope
使用方式
使用在類,接口,或者枚舉類上,也可以使用在方法上
作用
設(shè)定bean的作用域,默認(rèn)為單例singleton,可選擇為prototype原型模式,每次調(diào)用都有新的對象產(chǎn)生
源碼
@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
使用方式
使用在類,接口,或者枚舉類上,也可以使用在方法上,屬性,構(gòu)造器,
作用
設(shè)置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
使用方式
使用在方法之上
作用
將標(biāo)注的方法設(shè)置為當(dāng)前bean的初始化方法和銷毀方法
源碼
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PostConstruct {
}
@Documented
@Retention (RUNTIME)
@Target(METHOD)
public @interface PreDestroy {
}
@Value
使用方式
可以使用在屬性,方法,參數(shù),注釋之上
作用
為標(biāo)注屬性設(shè)置值
源碼
@Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Value {
String value();
}