Spring使用指南 ~ 4、ApplicationContext 配置详解

ApplicationContext 配置详解

一、应用程序事件

package com.luo.spring.guides.event.xml;

import org.springframework.context.ApplicationEvent;

public class MessageEvent extends ApplicationEvent {
    private final String msg;

    public MessageEvent(Object source, String msg) {
        super(source);
        this.msg = msg;
    }

    public String getMessage() {
        return msg;
    }
}

1、xml 形式

package com.luo.spring.guides.event.xml;

import org.springframework.context.ApplicationListener;

public class MessageEventListener implements ApplicationListener<MessageEvent> {
    @Override
    public void onApplicationEvent(MessageEvent event) {
        MessageEvent msgEvt = event;
        System.out.println("Received: " + msgEvt.getMessage());
    }
}
package com.luo.spring.guides.event.xml;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class Publisher implements ApplicationContextAware {
    private ApplicationContext ctx;

    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.ctx = applicationContext;
    }

    public void publish(String message) {
        ctx.publishEvent(new MessageEvent(this, message));
    }


}


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="publisher" class="com.luo.spring.guides.event.xml.Publisher"/>

    <bean id="messageEventListener" 
        class="com.luo.spring.guides.event.xml.MessageEventListener"/>
beans>

测试

package com.luo.spring.guides.event.xml;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/9 11:29
 * @description :
 */
public class Main {

    public static void main(String... args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:event/app-context-xml.xml");

        Publisher pub = (Publisher) ctx.getBean("publisher");
        pub.publish("I send an SOS to the world... ");
        pub.publish("... I hope that someone gets my...");
        pub.publish("... Message in a bottle");
    }
}

输出

Received: I send an SOS to the world…
Received: … I hope that someone gets my…
Received: … Message in a bottle

2、注解形式

package com.luo.spring.guides.event.domain;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

@Component
public class Publisher implements ApplicationContextAware {
    private ApplicationContext ctx;

    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        this.ctx = applicationContext;
    }

    public void publish(String message) {
        ctx.publishEvent(new MessageEvent(this, message));
    }
}
package com.luo.spring.guides.event.annotation;

import com.luo.spring.guides.event.domain.MessageEvent;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;

/**
 * @author : archer
 * @date : Created in 2022/12/9 11:35
 * @description :
 */
@Component
public class MessageEventListener {

    @EventListener(classes = {MessageEvent.class})
    public void messageEventListener(MessageEvent messageEvent){
        System.out.println("Received: " + messageEvent.getMessage());
    }
}

测试

package com.luo.spring.guides.event.annotation;

import com.luo.spring.guides.event.domain.Publisher;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * @author : archer
 * @date : Created in 2022/12/9 11:29
 * @description :
 */
public class Main {

    public static void main(String... args) {
        ApplicationContext ctx = new AnnotationConfigApplicationContext(
                "com.luo.spring.guides.event");

        Publisher pub = (Publisher) ctx.getBean("publisher");
        pub.publish("I send an SOS to the world... ");
        pub.publish("... I hope that someone gets my...");
        pub.publish("... Message in a bottle");
    }
}

输出

Received: I send an SOS to the world…
Received: … I hope that someone gets my…
Received: … Message in a bottle

二、访问资源

test.txt

Dreaming with a Broken Heart

测试

package com.luo.spring.guides.resource;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.FileUrlResource;
import org.springframework.core.io.Resource;

import java.io.File;

public class Main {
    public static void main(String... args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext();

        File file = File.createTempFile("test", "txt");
        file.deleteOnExit();

        Resource res1 = ctx.getResource("file://" + file.getPath());
        displayInfo(res1);

        Resource res2 = ctx.getResource("classpath:test.txt");
        displayInfo(res2);

        Resource res3 = ctx.getResource("http://www.google.com");
        displayInfo(res3);
    }

    private static void displayInfo(Resource res) throws Exception {
        System.out.println(res.getClass());
        if (!(res instanceof FileUrlResource)) {
            System.out.println(res.getURL().getContent());//FileUrlResource不能使用getURL().getContent()
        }
        System.out.println("");
    }
}

输出

class org.springframework.core.io.FileUrlResource

class org.springframework.core.io.ClassPathResource
sun.net.www.content.text.PlainTextInputStream@12405818

class org.springframework.core.io.UrlResource
sun.net.www.protocol.http.HttpURLConnection$HttpInputStream@400cff1a

三、profiles

  • 通过 -Dspring.profiles.active=highschool 指定要使用的配置文件(highschool 是 profile 中的值)
package com.luo.spring.guides.profiles.impl;

public class Food {
    private String name;

    public Food() {
    }

    public Food(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
package com.luo.spring.guides.profiles.impl;

import java.util.List;

public interface FoodProviderService {
    List<Food> provideLunchSet();
}
package com.luo.spring.guides.profiles.impl.kindergarten;

import com.luo.spring.guides.profiles.impl.Food;
import com.luo.spring.guides.profiles.impl.FoodProviderService;

import java.util.ArrayList;
import java.util.List;

public class KindergartenFoodProviderServiceImpl implements FoodProviderService {
    @Override
    public List<Food> provideLunchSet() {
        List<Food> lunchSet = new ArrayList<>();
        lunchSet.add(new Food("Milk"));
        lunchSet.add(new Food("Biscuits"));

        return lunchSet;
    }
}
package com.luo.spring.guides.profiles.impl.highschool;

import com.luo.spring.guides.profiles.impl.Food;
import com.luo.spring.guides.profiles.impl.FoodProviderService;

import java.util.ArrayList;
import java.util.List;

public class HighSchoolFoodProviderServiceImpl implements FoodProviderService {
    @Override
    public List<Food> provideLunchSet() {
        List<Food> lunchSet = new ArrayList<>();
        lunchSet.add(new Food("Coke"));
        lunchSet.add(new Food("Hamburger"));
        lunchSet.add(new Food("French Fries"));

        return lunchSet;
    }
}

1、xml 形式

highschool-config.xml



<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd"
        profile="highschool">

    <bean id="foodProviderService"
      class="com.luo.spring.guides.profiles.impl.highschool.HighSchoolFoodProviderServiceImpl"/>
beans>

kindergarten-config.xml



<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd"
        profile="kindergarten">

    <bean id="foodProviderService" 
      class="com.luo.spring.guides.profiles.impl.kindergarten.KindergartenFoodProviderServiceImpl"/>
beans>

测试

  • 启动类指定 -Dspring.profiles.active=highschool
package com.luo.spring.guides.profiles.xml;

import com.luo.spring.guides.profiles.impl.Food;
import com.luo.spring.guides.profiles.impl.FoodProviderService;
import org.springframework.context.support.GenericXmlApplicationContext;

import java.util.List;

//通过 -Dspring.profiles.active=highschool 指定要使用的配置文件
public class Main {
    public static void main(String... args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:profiles/*-config.xml");
        ctx.refresh();

        FoodProviderService foodProviderService =
            ctx.getBean("foodProviderService", FoodProviderService.class);

        List<Food> lunchSet = foodProviderService.provideLunchSet();

        for (Food food: lunchSet) {
            System.out.println("Food: " + food.getName());
        }

        ctx.close();
    }
}

输出

Food: Coke
Food: Hamburger
Food: French Fries

2、注解形式

package com.luo.spring.guides.profiles.annotation;


import com.luo.spring.guides.profiles.impl.FoodProviderService;
import com.luo.spring.guides.profiles.impl.highschool.HighSchoolFoodProviderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

/**
 * Created by iuliana.cosmina on 3/18/17.
 */
@Configuration
@Profile("highschool")
public class HighschoolConfig {

	@Bean
	public FoodProviderService foodProviderService(){
		return new HighSchoolFoodProviderServiceImpl();
	}
}
package com.luo.spring.guides.profiles.annotation;


import com.luo.spring.guides.profiles.impl.FoodProviderService;
import com.luo.spring.guides.profiles.impl.kindergarten.KindergartenFoodProviderServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;

/**
 * Created by iuliana.cosmina on 3/18/17.
 */
@Configuration
@Profile("kindergarten")
public class KindergartenConfig {

	@Bean
	public FoodProviderService foodProviderService(){
		return new KindergartenFoodProviderServiceImpl();
	}
}

测试

  • 启动类指定 -Dspring.profiles.active=highschool
package com.luo.spring.guides.profiles.annotation;

import com.luo.spring.guides.profiles.impl.Food;
import com.luo.spring.guides.profiles.impl.FoodProviderService;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

import java.util.List;

/**
 * Created by iuliana.cosmina on 3/18/17.
 */
public class Main {

	public static void main(String... args) {
		GenericApplicationContext ctx = new AnnotationConfigApplicationContext(
				KindergartenConfig.class,
				HighschoolConfig.class);

		FoodProviderService foodProviderService =
				ctx.getBean("foodProviderService", FoodProviderService.class);

		List<Food> lunchSet = foodProviderService.provideLunchSet();
		for (Food food : lunchSet) {
			System.out.println("Food: " + food.getName());
		}
		ctx.close();
	}
}

输出

Food: Coke
Food: Hamburger
Food: French Fries

四、Environment

1、PropertySource

对于 PropertySource,Spring 将按照以下默认顺序访问属性:

  • a、运行 JVM 的系统属性
  • b、环境变量
  • c、应用程序定义的属性

注意:用户可以通过 Environment 对 PropertySource 的访问属性的顺序进行调整。

1)、默认访问顺序
package com.luo.spring.guides.environment;

import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;

import java.util.HashMap;
import java.util.Map;

public class EnvironmentSampleLast {

    public static void main(String... args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.refresh();

        ConfigurableEnvironment env = ctx.getEnvironment();
        MutablePropertySources propertySources = env.getPropertySources();

        Map<String,Object> appMap = new HashMap<>();
        appMap.put("application.home", "application_home");
        appMap.put("user.home", "application_home");

        propertySources.addLast(new MapPropertySource("prospring5_MAP", appMap));

        System.out.println("user.home: " + System.getProperty("user.home"));
        System.out.println("JAVA_HOME: " + System.getenv("JAVA_HOME"));

        System.out.println("user.home: " + env.getProperty("user.home"));
        System.out.println("JAVA_HOME: " + env.getProperty("JAVA_HOME"));

        System.out.println("application.home: " + env.getProperty("application.home"));

        ctx.close();
    }
}

输出

user.home: C:\Users\Administrator
JAVA_HOME: D:\developer\Java\jdk1.8.0_231
user.home: C:\Users\Administrator
JAVA_HOME: D:\developer\Java\jdk1.8.0_231
application.home: application_home

2)、自定义访问循序
package com.luo.spring.guides.environment;

import org.springframework.context.support.GenericXmlApplicationContext;
import org.springframework.core.env.ConfigurableEnvironment;
import org.springframework.core.env.MapPropertySource;
import org.springframework.core.env.MutablePropertySources;

import java.util.HashMap;
import java.util.Map;

public class EnvironmentSampleFirst {

    public static void main(String... args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.refresh();

        ConfigurableEnvironment env = ctx.getEnvironment();
        MutablePropertySources propertySources = env.getPropertySources();

        Map<String,Object> appMap = new HashMap<>();
        appMap.put("user.home", "application_home");

        //该表检索优先级
        propertySources.addFirst(new MapPropertySource("prospring5_MAP", appMap));

        System.out.println("user.home: " + System.getProperty("user.home"));
        System.out.println("JAVA_HOME: " + System.getenv("JAVA_HOME"));

        System.out.println("user.home: " + env.getProperty("user.home"));
        System.out.println("JAVA_HOME: " + env.getProperty("JAVA_HOME"));

        System.out.println("user.home: " + env.getProperty("user.home"));

        ctx.close();
    }
}

输出

user.home: C:\Users\Administrator
JAVA_HOME: D:\developer\Java\jdk1.8.0_231
user.home: application_home
JAVA_HOME: D:\developer\Java\jdk1.8.0_231
user.home: application_home

五、国际化

  • 非 web 类的独立应用程序,应该使用依赖注入的方式来获取到 MessageSource 对象,再操作它来获取对应配置信息


<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:util="http://www.springframework.org/schema/util"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/util
         http://www.springframework.org/schema/util/spring-util.xsd">

    <bean id="messageSource" 
          class="org.springframework.context.support.ResourceBundleMessageSource"
      p:basenames-ref="basenames"/>

    <util:list id="basenames">
        <value>buttonsvalue>
        <value>labelsvalue>
    util:list>
beans>

classpath:labels_de_DE.properties

msg=Mein dummer Mund hat mich in Schwierigkeiten gebracht
nameMsg=Mein Name ist {0} {1}

classpath:labels_en_EN.properties

msg=My stupid mouth has got me in trouble
nameMsg=My name is {0} {1}

classpath:buttons_de_DE.properties

buttonName=de

classpath:buttons_en_EN.properties

buttonName=en

测试

package com.luo.spring.guides.messagesource;

import org.springframework.context.support.GenericXmlApplicationContext;

import java.util.Locale;

public class Main {
    public static void main(String... args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:i18n/app-context-xml.xml");
        ctx.refresh();

//        Locale english = Locale.ENGLISH;
        Locale english = new Locale("en", "EN");
        Locale german = new Locale("de", "DE");

        System.out.println(ctx.getMessage("msg", null, english));
        System.out.println(ctx.getMessage("msg", null, german));

        System.out.println(ctx.getMessage("nameMsg", new Object[] { "John",
                "Mayer" }, english));
        System.out.println(ctx.getMessage("nameMsg", new Object[] { "John",
                "Mayer" }, german));
        
        System.out.println(ctx.getMessage("buttonName", null, english));
        System.out.println(ctx.getMessage("buttonName", null, german));

        ctx.close();
    }
}

输出

My stupid mouth has got me in trouble
Mein dummer Mund hat mich in Schwierigkeiten gebracht
My name is John Mayer
Mein Name ist John Mayer
en
de

六、使用 JSR-330 注解进行配置

Spring 的注解相比 JSR-330 注解更加丰富和灵活,以下是两者之间的主要差异(不建议混合使用):

  • 当使用 Spring 的 @Autowired 注解时,可以指定 required 属性来表明必须完成 DI(也可以使用 @Required 注解),而对于 JSR-330 的 @Inject 注解,则没有与之等价的属性。Spring 还提供了 @Qualifier 注解来更精细的控制基于限定符名称的依赖项的自动装配。
  • JSR-330 仅支持单例和非单例 bean 的作用域,Spring 支持更多。
  • Spring 可以使用 @Lazy 注解来指示 Spring 仅在程序请求时再实例化 bean。JSR-330 没有与之等价的注解。
package com.luo.spring.guides.jsr330;

import javax.inject.Inject;
import javax.inject.Named;

@Named("messageProvider")
public class MessageProvider {
    private String message = "Default message";

    @Inject
    @Named("message")
    public MessageProvider(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }
}
package com.luo.spring.guides.jsr330;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;

@Named("messageRenderer")
@Singleton
public class MessageRenderer {
    @Inject
    @Named("messageProvider")
    private MessageProvider messageProvider = null;

    public void render() {
        if (messageProvider == null) {
            throw new RuntimeException(
                "You must set the property messageProvider of class:"
                + MessageRenderer.class.getName());
        }

        System.out.println(messageProvider.getMessage());
    }

    public MessageProvider getMessageProvider() {
        return this.messageProvider;
    }
}
package com.luo.spring.guides.jsr330;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * @author : archer
 * @date : Created in 2022/12/9 18:22
 * @description :
 */
@ComponentScan(basePackages = {"com.luo.spring.guides.jsr330"})
@Configuration
public class Jsr330Config {

    @Bean
    String message(){
        return "Gravity is working against me";
    }
}

测试

package com.luo.spring.guides.jsr330;

import com.luo.spring.guides.profiles.annotation.HighschoolConfig;
import com.luo.spring.guides.profiles.annotation.KindergartenConfig;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.GenericApplicationContext;

public class Main {

	public static void main(String... args) {
		GenericApplicationContext ctx = new AnnotationConfigApplicationContext(Jsr330Config.class);

		MessageRenderer renderer = ctx.getBean("messageRenderer", MessageRenderer.class);
		renderer.render();

		ctx.close();
	}
}

输出

Gravity is working against me

七、结合 Groovy

  • 需要添加 groovy-all 依赖

maven 依赖


<dependency>
    <groupId>org.codehaus.groovygroupId>
    <artifactId>groovy-allartifactId>
    <version>2.4.5version>
dependency>
package com.luo.spring.guides.groovy;

/**
 * Created by iuliana.cosmina on 2/25/17.
 */
public class Singer {
    private String name;
    private int age;

    public void setName(String name) {
        this.name = name;
    }

    public void setAge(int age) {
        this.age = age;
    }
        
    public String toString() {
        return "\tName: " + name + "\n\t" + "Age: " + age;
    }
}
package com.luo.spring.guides.groovy

import com.luo.spring.guides.groovy.Singer

beans {
    singer(Singer, name: 'John Mayer', age: 39)
}

测试

package com.luo.spring.guides.groovy;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.GenericGroovyApplicationContext;

public class Main {

	public static void main(String... args) {
		ApplicationContext context = new GenericGroovyApplicationContext("classpath:groovy/beans.groovy");
		Singer singer = context.getBean("singer", Singer.class);
		System.out.println(singer);
	}
}

输出

Name: John Mayer

Age: 39

八、property-placeholder

package com.luo.spring.guides.propertyplaceholder;

public class AppProperty {
    private String applicationHome;
    private String userHome;

    public String getApplicationHome() {
        return applicationHome;
    }

    public void setApplicationHome(String applicationHome) {
        this.applicationHome = applicationHome;
    }

    public String getUserHome() {
        return userHome;
    }

    public void setUserHome(String userHome) {
        this.userHome = userHome;
    }
}


<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"
       xmlns:p="http://www.springframework.org/schema/p"
       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">

    <context:property-placeholder local-override="true"
         location="classpath:propertyplaceholder/application.properties"/>

    <bean id="appProperty" class="com.luo.spring.guides.propertyplaceholder.AppProperty"
          p:applicationHome="${application.home}"
          p:userHome="${user.home}"/>
beans>
application.home=application_home
user.home=/home/jules-new

测试

package com.luo.spring.guides.propertyplaceholder;

import org.springframework.context.support.GenericXmlApplicationContext;

public class Main {
    public static void main(String... args) {
        GenericXmlApplicationContext ctx = new GenericXmlApplicationContext();
        ctx.load("classpath:propertyplaceholder/app-context-xml.xml");
        ctx.refresh();

        AppProperty appProperty = ctx.getBean("appProperty", AppProperty.class);

        System.out.println("application.home: " + appProperty.getApplicationHome());
        System.out.println("user.home: " + appProperty.getUserHome());

        ctx.close();
    }
}

输出

application.home: application_home
user.home: /home/jules-new

你可能感兴趣的:(#,Spring系列,spring,java,前端)