概述
JavaConfig是Spring的一个子项目,它旨在通过Java类的方式提供Bean的定义信息,在Spring4.0的版本,JavaConfig正式成为Spring4.0的核心功能。
使用Java类提供Bean定义信息
普通的POJO只要标注了@Configuration注解,就可以为Spring容器提供Bean定义的信息,每个标注了@Bean的类方法都相当于提供一个Bean的定义信息。
实例
代码已托管到Github—> https://github.com/yangshangwei/SpringMaster
POJO
package com.xgj.ioc.javaConfig; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; // 将一个POJO标注为定义Bean的配置类 @Configuration public class Teacher { /** * * * @Title: studentOne * * @Description: 定义了一个Bean,并提供了Bean的实例化逻辑 * * @return * * @return: StudentOne */ @Bean public StudentOne studentOne() { return new StudentOne(); } /** * * * @Title: studentTwo * * @Description: 定义了一个Bean,并提供了Bean的实例化逻辑 * * @return * * @return: StudentTwo */ @Bean public StudentTwo studentTwo() { return new StudentTwo(); } public void arrangeStudent() { studentOne().doCleanWork(); studentTwo().doHomeWork(); } }
package com.xgj.ioc.javaConfig; public class StudentOne { public void doCleanWork() { System.out.println("StudentOne will do CleanWork"); } }
package com.xgj.ioc.javaConfig; public class StudentTwo { public void doHomeWork() { System.out.println("StudentTwo will do HomeWork"); } }
测试类
package com.xgj.ioc.javaConfig; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class JavaConfigTest { public static void main(String[] args) { ApplicationContext ctx = new AnnotationConfigApplicationContext( Teacher.class); ctx.getBean("teacher", Teacher.class).arrangeStudent(); } }
运行结果
分析
Teacher类的定义出标注了@Configuration注解,说明这个类可以用于为Spring提供Bean的定义信息。
该类的方法可以标注@Bean注解,Bean的类型由方法返回值的类型决定,名称默认和方法名同名,当然也可以通过入参显示指定Bean名称,比如@Bean(name=”coolStudent”).
@Bean所标注的方法体提供了Bean的实例化逻辑。
studentOne()和studentTwo()方法分别定义了一个StudentOne 和 StudentTwo类型的Bean, 他们的Bean名称分别为 studentOne 和 studentTwo。
在arrangeStudent()方法中 注入了上面实例化的两个Bean。
以上配置和下面的xml是等效的
<bean id="studentOne" class="com.xgj.ioc.javaConfig.StudentOne"/> <bean id="studentTwo" class="com.xgj.ioc.javaConfig.StudentTwo"/> <bean id="teacher" class="com.xgj.ioc.javaConfig.Teacher" p:sutdentOne-ref="studentOne" p:studentTwo-ref="studentTwo"/>
基于Java类的配置方式和基于XML或者基于注解的配置方式相比,前者通过代码编程的方式可以更加灵活的实现Bean的实例化及Bean之间的装配,后两者都是通过配置声明的方式,在灵活性上要稍逊一些,但在配置上要更简单一些。
使用基于Java类的配置信息启动Spring容器
1.直接通过@Configuration启动Spring容器
Spring提供了AnnotationConfigApplicationContext类,它能够直接通过标注@Configuration的Java类启动Spring容器。
通过AnnotationConfigApplicationContext的构造函数加载配置类
比如我们上面的那个例子的测试类
package com.xgj.ioc.javaConfig; import org.springframework.context.ApplicationContext; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class JavaConfigTest { public static void main(String[] args) { // (1)通过构造函数加载配置类 ApplicationContext ctx = new AnnotationConfigApplicationContext( Teacher.class); ctx.getBean("teacher", Teacher.class).arrangeStudent(); } }
在(1)处,通过AnnotationConfigApplicationContext类的构造函数直接传入标注了@Configuration的JAVA类,这届用该类中提供的Bean定义信息启动Spring容器。
通过编码的方式加载多个@Configuration配置类,然后通过刷新容器应用这些配置类
package com.xgj.ioc.javaConfig; import org.springframework.context.annotation.AnnotationConfigApplicationContext; public class JavaConfigTest { public static void main(String[] args) { // 通过构造函数加载配置类 // ApplicationContext ctx = new AnnotationConfigApplicationContext( // Teacher.class); AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(); // 注册@Configuration的配置类,可注册多个 ctx.register(Teacher.class); // 刷新容器以应用这些注册的配置类 ctx.refresh(); Teacher teacher = ctx.getBean("teacher", Teacher.class); teacher.arrangeStudent(); } }
通过@Import将多个配置类组装到一个配置类中,然后仅需注册这个组装好的配置类 ,启动容器
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.Import; @Configuration @Import(DaoConfig.class) public class ServiceConfig { @Autowired private DaoConfig daoConfig; @Bean public LogonService logonService(){ LogonService logonService = new LogonService(); System.out.println(daoConfig.logDao() == daoConfig.logDao()); logonService.setLogDao(daoConfig.logDao()); logonService.setUserDao(daoConfig.userDao()); return logonService; } }
AnnotationConfigApplicationContext的主要方法
2.通过XML配置文件引用@Configuration配置
标注了@Configuration的配置类和标注了@Component的类一样也是一个Bean, 同样的 它也可以被Spring的<context:component-scan>扫描到。 因此如果希望将配置类组装到XML的配置文件中,通过XML的配置文件启动Spring,这仅需要在XML子中通过<context:component-scan>扫描到相应的配置类即可。
我们改造下上面的测试类
增加配置文件:
<?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 http://www.springframework.org/schema/context/spring-context.xsd"> <!-- (1)声明Context命名空间以及Schema文件 (2)扫描类包以及应用注解定义的bean resource-pattern 看需求,可配置可不配置 --> <context:component-scan base-package="com.xgj.ioc.javaConfig" resource-pattern="Teacher.class" /> </beans>
package com.xgj.ioc.javaConfig; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class JavaConfigTest { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext( "classpath:com/xgj/ioc/javaConfig/beans.xml"); Teacher teacher = ctx.getBean("teacher", Teacher.class); teacher.arrangeStudent(); } }
同样也可以正确的加载并实例化Bean
2017-07-31 22:03:02,093 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@d167d36: startup date [Mon Jul 31 22:03:02 BOT 2017]; root of context hierarchy 2017-07-31 22:03:02,176 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/ioc/javaConfig/beans.xml] StudentOne will do CleanWork StudentTwo will do HomeWork
3.通过@Configuration配置类引用XML配置信息
假设bean中有两个Bean ,如下
<bean id="userDao" class="com.xgj.ioc.javaConfig.UserDao"/> <bean id="logDao" class="com.xgj.ioc.javaConfig.LogDao"/>
在@Configuration配置类中可以直接通过@ImportResource引入XML的配置那文件,这样就就可以直接通过@Autowired引用xml配置文件中定义的Bean。
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.context.annotation.ImportResource; @Configuration @ImportResource("classpath:com/xgj/ioc/javaConfig/beans.xml") public class LogonAppConfig { @Bean @Autowired public LogonService logonService(UserDao userDao,LogDao logDao){ LogonService logonService = new LogonService(); logonService.setUserDao(userDao); logonService.setLogDao(logDao); return logonService; } }
通过@ImportResource引入XML配置文件
通过@Bean定义一个LogonService 的bean
通过@Autowired自动注入userDao和logDao ,这两个Bean是在XML配置文件中定义的。
需要说明的是,@ImportResource引入XML配置文件,不是@Autowired处可成功注入到对应Bean的前提条件。 只要不同形式的Bean定义信息能够加载到Spring容器中,Spring就可以智能的完成Bean之间的装配。