美文网首页我爱编程
Spring Boot 之 Spring Java Config

Spring Boot 之 Spring Java Config

作者: 刘昊2018 | 来源:发表于2017-12-20 16:40 被阅读822次

    摘要

    Spring4 以后,官方推荐我们使用Java Config来代替applicationContext.xml,声明将Bean交给容器管理。
    在Spring Boot中,Java Config的使用也已完全替代了applicationContext.xml。实现了xml的零配置。所以无论从Spring的演进,还是学习Spring Boot的需要,都应该深入学习Spring Java Config的使用方法。这篇文章主要从以下几个方面进行介绍:

    • Spring java Config 入门程序
    • bean标签的使用
    • bean的依赖
    • 自动扫描
    • import 和 importResource
    • properties文件的加载及占位
    • profile

    Spring Java Config入门介绍及简单程序

    回顾以前的applicationContext.xml配置方式,我们会将需要使用bean通过xml的形式来配置,那么Java Config的方式,不需要多思考,就可以判断我们应该将bean配置在一个Java文件中,而且这个Java文件应当被Spring容器所识别。我们看如下这个例子:

    创建一个bean类
    public class SomeBean {
        public void doWork() {
            System.out.println("do work...");
        }
    }
    

    其中,doWork是逻辑方法。

    创建一个Config类
    @Configuration
    public class Config {
        @Bean
        public SomeBean someBean() {
            return new SomeBean();
        }
    }
    

    需要注意的是,我们在config类上添加了一个@configuration的注解,见名知意,我们可以理解为Spring中的配置类。在返回值为SomeBeansomeBean方法上我们添加了一个@Bean注解,也不难理解,返回的new SomeBean对象将交由Spring容器进行管理。

    测试
    public class Test {
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
            SomeBean sb = context.getBean(SomeBean.class);
            sb.doWork();
        }
    }
    

    这里,我们创建了一个AnnotationConfigApplicationContext对象,传入了Config.class后,得到了SomeBean对象。

    do work...
    

    以上就是Spring Java Config 配置bean的最简单的程序,对不喜欢xml配置的开发人员还是比较有优势的。
    我们知道,在xml中,一般是这样配置的:

    <bean id="someBean" class="com.springboot.javaconfig.SomeBean" initMethod="init" destroyMethod="destroy" ref="otherBean" scope="singlon"
    

    一个完整的bean配置包括了 id,class,initMethod,destroyMethodref,scope

    那么,在Java Config如何配置这些属性呢?其实也是很简单的,我们修改第一个例子的代码:

    public class SomeBean {
    
        private void init() {
            System.out.println("init...");
        }
    
        public void doWork() {
            System.out.println("do work...");
        }
    
        private void destroy() {
            System.out.println("destroy...");
        }
    
    }
    

    增加了init,destroy方法。

    @Configuration
    public class Config {
    
        @Bean(initMethod = "init",destroyMethod = "destroy")
        public SomeBean someBean() {
            return new SomeBean();
        }
    }
    

    在bean注解上,属性指向对应的方法名。

    public class Test {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
            SomeBean sb1 = context.getBean(SomeBean.class);
            System.out.println(sb1);
    
            SomeBean sb2 = context.getBean(SomeBean.class);
            System.out.println(sb2);
            context.close();
        }
    }
    

    输出结果为:

    init...
    com.spring.SomeBean@16022d9d
    com.spring.SomeBean@16022d9d
    destroy...
    

    从这个程序我们可以看出如下信息:

    • init,destroy方法都在相应的阶段被调用
    • 两次创建的SomeBean实例指向同一个地址,说明Spring容器给我们创建的SomeBean对象时单例的。
    其它

    如果希望创建了一个多例的bean,可以这样书写:

    @Scope("prototype")
    public class SomeBean {
    }
    

    如果希望使用id和class共同查找bean,可以这样书写:

    SomeBean sb = context.getBean("someBean",SomeBean.class);
    

    需要特别注意的是,Spring默认使用Config中的函数名作为该bean的id。

    bean的依赖

    在xml中,我们使用value来配置注入简单值,ref来配置注入其他对象,那么在Java Config中如何实现呢?我们来继续编写代码:

    新建一个bean类
    public class OtherBean {
    
    }
    
    修改SomeBean和Config类
    public class SomeBean {
    
        @Autowired
        private OtherBean otherBean;
    
        public void sayHello() {
            System.out.println(otherBean);
        }
    
    }
    
    @Configuration
    public class Config {
    
        @Bean
        public SomeBean someBean() {
            return new SomeBean;
        }
    
        @Bean
        public OtherBean otherBean () {
            return new OtherBean();
        }
    }
    

    此时,我们将OtherBean纳入spring容器进行管理,在SomeBean类中对OtherBean的实例进行注入。得到结果:

    com.spring.OtherBean@51b279c9
    

    由此,实现了Java Config中的依赖注入,只不过也就是将需要依赖的bean也加入Config类用bean以修饰。
    当然,我们也可以不使用@AutoWired标签,而通过set方法注入。

    
    @Configuration
    public class Config {
    
        @Bean
        public SomeBean someBean(OtherBean otherBean) {
            SomeBean someBean = new SomeBean();
            // 1
            someBean.setOtherBean(new OtherBean());
            // 2
            someBean.setOtherBean(otherBean());
    
            // 3
            someBean.setOtherBean(otherBean);
            return someBean;
        }
    
        @Bean
        public OtherBean otherBean () {
            return new OtherBean();
        }
    }
    

    set注入方法比较多,可以自行创建一个OtherBean对象,因为都在Config类中,也可以调用otherBean()方法,也可以在参数列表中进行传入,参数名要使用OtherBean的方法名。因为OtherBean类型的可能有多个对象。

    Java Config 和 注解配置混用

    我们知道,spring为我们提供了诸如@component,@controller,@service,@repositroy这类标签,它们增加了类的语义,然后将对应的类加入到了spring容器进行管理,也是避免了在xml中去配置。将Java Config和注解配置混用是我们在日常开发中经常使用的方式,我们来看如下代码,模拟MVC三层架构:

    LoginDAO:
    @Repository
    public class LoginDAO {
        public void login() {
            System.out.println("login...");
        }
    }
    
    LoginService
    @Service
    public class LoginService {
    
        @Autowired
        private LoginDao loginDao;
    
    
        public void login() {
            loginDao.login();
        }
    }
    
    LoginController
    @RequestMapping("/user")
    @RestController
    public class LoginController {
    
        @Autowired
        private LoginService loginService;
    
        @RequestMapping(path = "/login",method = RequestMethod.POST)
        public void login() {
            loginService.login();
        }
    }
    
    Java Config
    @ComponentScan(basePackages = "com.spring")
    @Configuration
    public class Config { 
    }
    
    public class Test {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
    
            LoginController controller = context.getBean("loginController",LoginController.class);
    
            controller.login();
        }
    }
    

    输出结果:

    login...
    

    解读:我们并没有将LoginDAO,LoginService,LoginController纳入Config,用@Bean修饰,而是使用了注解配置,在Config类中通过ComponentScan标签,将它们纳入sping容器。通过测试, 我们发现,Java Config 和 注解配置的混合使用时可行的。

    Java Config 和 applicationContext.xml混用

    有时候,我们会遇到必须使用xml配置的情况,这时候,我们可以这样来操作:

    创建applicationContext.xml文件
    <bean id="xmlBean" class="com.spring.XMLBean"/>
    
    修改Config
    @ImportResource("com/spring/applicationContext.xml")
    @ComponentScan(basePackages = "com.spring")
    @Configuration
    public class Config {
    }
    

    运行结果:

    com.spring.XMLBean@7bb58ca3
    

    Config类上使用@ImportResource标签,就可以将在xml配置的bean引入到spring容器。

    占位符配置

    自定义datasource
    public class DataSource {
        private String url;
        private String driverClass;
        private String userName;
        private String password;
        // get()
        // set()
        // constructor()
    }
    

    在xml中,我们配置datasource时往往将连接信息封装在db.properties中:

    driverClass=com.mysql.jdbc.driver
    url=jdbc:mysql://localhost:3306/my-database
    username=root
    password=root
    

    在xml中使用占位的方式来获取:

    <context:property-placeholder location="com/spring/db.properties"/>
    <bean id="dataSource" class="com.spring.DataSource">
            <property name="url" value="${url}"/>
            <property name="driverClass" value="${driverClass}"/>
            <property name="userName" value="${user}"/>
            <property name="password" value="${password}"/>
    </bean>
    
    测试
    public class Test {
        public static void main(String[] args) {
            AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
            DataSource dataSource = context.getBean("dataSource",DataSource.class);
            System.out.println(dataSource);
        }
    }
    

    输出结果:

    DataSource{url='jdbc:mysql://localhost:3306/test', driverClass='com.mysql.jdbc.driver', userName='root', password='root'}
    

    那么如何在Config中解读占位配置呢?继续编写代码:

    以示区分,我们修改一下,db.properties:
    driverClass=com.mysql.jdbc.driver
    url=jdbc:mysql://localhost:3306/test
    user=admin
    password=admin
    
    修改Config
    //@ImportResource("com/spring/applicationContext.xml")
    @PropertySource("com/spring/db.properties")
    @ComponentScan(basePackages = "com.spring")
    @Configuration
    public class Config {
    
        @Autowired
        private Environment env;
    
        @Bean
        public DataSource dataSource() {
            return new DataSource(env.getProperty("url"),env.getProperty("driverClass"),
                    env.getProperty("user"),env.getProperty("password"));
        }
    }
    

    此时,我们先是去掉了@ImportResource标签,因为已经不需要在xml中配置了,又使用了一个新的标签@PropertySource,来加载db,properties文件,然后又注入了一个env对象,Environment类继承了PropertyResolver接口,专门用来解析properties。

    输出结果:

    DataSource{url='jdbc:mysql://localhost:3306/test', driverClass='com.mysql.jdbc.driver', user='admin', password='admin'}
    

    可以看到,加载properties文件,在Spring Java Config也提供了支持。

    Profile

    相关文章

      网友评论

        本文标题:Spring Boot 之 Spring Java Config

        本文链接:https://www.haomeiwen.com/subject/dzngwxtx.html