adaptive spring applications with profiles and more

63
© 2013 SpringOne 2GX. All rights reserved. Do not distribute without permission. Adaptive Spring Applications with Profiles and More by Josh Long and Kevin Nilson Friday, September 20, 13

Upload: spring-io

Post on 01-Nov-2014

1.763 views

Category:

Technology


5 download

DESCRIPTION

Speakers: Josh Long and Kevin Nilson It’d be nice to assume everything remains the same from one environment to another, but the realities of today’s deployment targets (clouds, app servers, etc.) make this difficult. An application may target one in-memory database in development and target a traditional database in production. A/B testing is a common practice that lets you incrementally expose potentially high risk features. Feature switches can be invaluable; should something go wrong, you can revert to a known state. All of these use cases, and more, can be handled using the Spring framework. Join JavaOne Rock Star and Java Champion Kevin Nilson and Spring Developer Advocate Josh Long for a look at how you can run your application in differing environments using the Spring Framework.

TRANSCRIPT

Page 1: Adaptive Spring Applications with Profiles and More

© 2013 SpringOne 2GX. All rights reserved. Do not distribute without permission.

Adaptive Spring Applications with Profiles and More

by Josh Long and Kevin Nilson

Friday, September 20, 13

Page 2: Adaptive Spring Applications with Profiles and More

Developer Advocateinterested in big data, the open web, cloud and all things Spring

2

About Josh Long

@[email protected]

Friday, September 20, 13

Page 3: Adaptive Spring Applications with Profiles and More

KEVIN NILSON

About  Kevin  Nilson

• Chromecast  Developer  Advocate  -­‐  Google• Java  Champion• 3  Time  JavaOne  Rock  Star• Co-­‐Author  of  Web  2.0  Fundamentals• Leader  Silicon  Valley  Java  User  Group• Leader  Silicon  Valley  JavaScript  Meetup• Leader  Silicon  Valley  Google  Developer  Group• Taught  7  Course  @  College  of  San  Mateo,  CIS

Friday, September 20, 13

Page 4: Adaptive Spring Applications with Profiles and More

WELCOME

Welcome

Friday, September 20, 13

Page 5: Adaptive Spring Applications with Profiles and More

ADAPTING THE SYSTEM AT CONFIGURATION TIME

Adapting Beans at Construction Time

Friday, September 20, 13

Page 6: Adaptive Spring Applications with Profiles and More

TAILORING BEAN CONSTRUCTION

manages the life cycle of beans in the ApplicationContext

<bean init-method="init" class="some.Bean" destroy-method="destroy"> ... </bean>

package some;

public class Bean { public void init(){ } public void destroy(){ }}

Friday, September 20, 13

Page 7: Adaptive Spring Applications with Profiles and More

TAILORING BEAN CONSTRUCTION

manages the life cycle of beans in the ApplicationContext

package some;

public class Bean {

@PostConstruct public void init(){ }

@PreDestroy public void destroy(){ }

}

Friday, September 20, 13

Page 8: Adaptive Spring Applications with Profiles and More

TAILORING BEAN CONSTRUCTION

manages the life cycle of beans in the ApplicationContext

package some;

public class Bean implements InitializingBean, DisposableBean {

public void afterPropertiesSet(){ }

public void dispose(){ }

}

Friday, September 20, 13

Page 9: Adaptive Spring Applications with Profiles and More

TAILORING BEAN CONSTRUCTION

manages the life cycle of beans in the ApplicationContext

Spring uses the no-arg constructor of your bean to create it.

Friday, September 20, 13

Page 10: Adaptive Spring Applications with Profiles and More

TAILORING BEAN CONSTRUCTION

manages the life cycle of beans in the ApplicationContext

Historically: we’ve used FactoryBeans to mix things up

public class CronTriggerFactoryBean implements FactoryBean<CronTrigger> { ...

public CronTrigger getObject(){ ... }}

Friday, September 20, 13

Page 11: Adaptive Spring Applications with Profiles and More

TAILORING BEAN CONSTRUCTION

@PropertySource("/config.properties")@Configurationpublic class ServiceConfiguration {

@Bean public DataSource postgres(Environment e) { // ... }

@Bean public CustomerService customerService(DataSource ds) { return new CustomerService(ds); }}

but with Java configuration, you don’t need the indirection anymore..

Friday, September 20, 13

Page 12: Adaptive Spring Applications with Profiles and More

TAILORING BEAN CONSTRUCTION

If you think about it... factory methods are everywhere!

(They’re even a pattern!)javax.inject.Provider<DataSource> dataSourceProvider

o.sf.beans.FactoryBean<DataSource> dataSourceFactoryBean

java.util.concurrent.Callable<DataSource> dataSourceCallable ...?and what about..

Friday, September 20, 13

Page 13: Adaptive Spring Applications with Profiles and More

TAILORING BEAN CONSTRUCTION

factory methods are going to be awesome with Java 8

Provider<DataSource> dataSourceProvider = ()->{ // ...};

Friday, September 20, 13

Page 14: Adaptive Spring Applications with Profiles and More

ADAPTING THE SYSTEM AT CONFIGURATION TIME

The Environment and Profiles

Friday, September 20, 13

Page 15: Adaptive Spring Applications with Profiles and More

ASKING QUESTIONS OF THE ENVIRONMENT...

the environment in which an application runs isn’t always certain...

Friday, September 20, 13

Page 16: Adaptive Spring Applications with Profiles and More

ASKING QUESTIONS OF THE ENVIRONMENT...

the Spring Environment abstraction helps.

am I?where

@Inject Environment env;

String whereAmI = env.getProperty(“user.dir”);

Friday, September 20, 13

Page 17: Adaptive Spring Applications with Profiles and More

ASKING QUESTIONS OF THE ENVIRONMENT...

the Spring Environment abstraction helps.

@Inject Environment env;

String whoAreYou = env.getProperty(“database.url”);

are who

you?

Friday, September 20, 13

Page 18: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Demousing the Environment

Friday, September 20, 13

Page 19: Adaptive Spring Applications with Profiles and More

ASKING QUESTIONS OF THE ENVIRONMENT...

Values may come from anywhere.

You can add your own PropertySource implementations, too.ApplicationContext context = ...ConfigurableEnvironment environment = (ConfigurableEnvironment) context.getEnvironment();

Map<String, Object> map = new HashMap<String, Object>();map.put(“value1”, “url”);

MapPropertySource mapPropertySource = new MapPropertySource( "dbConfig", map);

environment.getPropertySources().addFirst( mapPropertySource );

Friday, September 20, 13

Page 20: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

for convenience, just use the @PropertySource annotation

@PropertySource("/config.properties")@Configurationpublic class ServiceConfiguration {

Friday, September 20, 13

Page 21: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

then you can use the Environment in your Java configuration...

@PropertySource("/config.properties")@Configurationpublic class ServiceConfiguration { @Bean public DataSource database(Environment env) { try { String user = env.getProperty(“db.user”), pw = env.getProperty(“db.password”), url = env.getProperty(“db.url”); Class<? extends Driver> driverClass = env.getPropertyAsClass( “db.driverClass”, Driver.class);

Friday, September 20, 13

Page 22: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Demousing @PropertySource

Friday, September 20, 13

Page 23: Adaptive Spring Applications with Profiles and More

PROFILES

Multiple ImplementationsAllow you to provide one implementation for production and other versions that may not really work...

Friday, September 20, 13

Page 24: Adaptive Spring Applications with Profiles and More

PROFILES

Mocking for TestingMock anything that is non-predictive slow

Testing Edge conditions what-if scenarios

Friday, September 20, 13

Page 25: Adaptive Spring Applications with Profiles and More

PROFILES

Mocking for ProductivityServices are not always available

Services are often slow

Start the front-end when you start the back-end

Friday, September 20, 13

Page 26: Adaptive Spring Applications with Profiles and More

PROFILES

@Servicepublic class VideoSearchYoutube implements VideoSearch { public List<String> lookupVideo(String searchTerm) throws Exception{ ... return results;

@Servicepublic class VideoSearchMock implements VideoSearch { public List<String> lookupVideo(String searchTerm) throws Exception{ ... return results;

Friday, September 20, 13

Page 27: Adaptive Spring Applications with Profiles and More

PROFILES

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type [savetheenvironment.embedded.video.VideoSearch] is defined: expected single matching bean but found 2: videoSearchMock,videoSearchYouTube

Friday, September 20, 13

Page 28: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

no more external .xml contexts!

Friday, September 20, 13

Page 29: Adaptive Spring Applications with Profiles and More

PROBLEM WITH ANNOTATIONS

@Profile(“VideoYoutube”)@Servicepublic class VideoSearchYoutube implements VideoSearch { public List<String> lookupVideo(String searchTerm) throws Exception{ ... return results;

@Profile(“VideoMock”)@Servicepublic class VideoSearchMock implements VideoSearch { public List<String> lookupVideo(String searchTerm) throws Exception{ ... return results;

Friday, September 20, 13

Page 30: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

you can also use profiles in your unit tests.

@ContextConfiguration(classes = {ServiceConfiguration.class})@ActiveProfiles(“mock”)@RunWith(SpringJUnit4ClassRunner.class)public class VideoSearchTest {

@Inject private VideoSearch videoSearch;

@Test public void testVideoSearch() throws Exception { assertEquals( 2, videoSearch.lookupVideo("Kevin Nilson").size()); }

..

Friday, September 20, 13

Page 31: Adaptive Spring Applications with Profiles and More

ADAPTIVE SPRING

Demousing @Profile

Friday, September 20, 13

Page 32: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

profiles tag groups of beans into sets

dev cloud qa

dataSource

txManager

mongo

dataSource

txManager

mongo

dataSource

txManager

mongo

Friday, September 20, 13

Page 33: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

the Environment also offers access to “profiles.”

profiles let you tag groups of beans, and enable them selectively.

Friday, September 20, 13

Page 34: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

It’s easy to tag a bean with a profile in Java configuration

@Configuration @Profile(“dev”)class LocalConfiguration { }

@Configuration @Profile(“production”) class ProductionConfiguration { }

Friday, September 20, 13

Page 35: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

It’s easy to tag a bean with a profile on a bean-by-bean basis

@Component@Profile(“dev”)class InMemoryCustomerRepository implements CustomerRepository { // ...}

@Component@Profile(“production”) class JdbcCustomerRepository implements CustomerRepository { // ...}

Friday, September 20, 13

Page 36: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

You specify a profile on the ApplicationContext’s Environment

ApplicationContext ac = ..

Environment env = ac.getEnvironment();env.setActiveProfiles( production ? “production” : “dev” );

ac.register(ServiceConfiguration.class);ac.refresh();

Friday, September 20, 13

Page 37: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

You specify a profile with a system environment variable

-Dspring.profiles.active=dev,qa

Friday, September 20, 13

Page 38: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

You specify a profile with a init-param or context-param in web.xml

<servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>spring.profiles.active</param-name> <param-value>qa,dev</param-value> </init-param></servlet>

Friday, September 20, 13

Page 39: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

You specify a profile in code in a Servlet (web.xml) environment with an ApplicationContextInitializer:

public class MyApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {

public void initialize(ConfigurableApplicationContext applicationContext) {

String p = (Math.random() > .5 ? "production" : "qa"); applicationContext.getEnvironment().setActiveProfile(p); } }

Friday, September 20, 13

Page 40: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Then simply register it with the DispatcherServlet.

It’ll be invoked before any beans are read and configured.

<servlet> <servlet-name>spring</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextInitializerClasses</param-name> <param-value> app.MyApplicationContextInitializer </param-value> </init-param></servlet>

Friday, September 20, 13

Page 41: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

it’s even simpler with Servlet 3 environments:

class CrmAbstractDispatcherServletInitializer extends AbstractDispatcherServletInitializer {

@Override protected WebApplicationContext createServletApplicationContext() { boolean production = // value is presumably obtained externally AnnotationConfigWebApplicationContext ac = .. ac.getEnvironment().setActiveProfiles( production ? "production" : "dev" ); ac.register(WebMvcConfiguration.class); ac.refresh(); return ac; }

@Override protected String[] getServletMappings() { return new String[]{"/*"}; }

@Override protected WebApplicationContext createRootApplicationContext() { return null; }}Friday, September 20, 13

Page 42: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

You specify a profile for Spring Boot applications in the application.properties file

$>cat src/main/resources/application.properties

# Spring Boot will read this filespring.profiles.active=dev,qa

Friday, September 20, 13

Page 43: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Some profiles are special (in certain contexts).

default is activated... by default.

Cloud Foundry activates the cloud profile if it’s available.

(we’re all special in certain contexts!)

Friday, September 20, 13

Page 44: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Demousing EC2 Tags to Configure Profiles

http://tinyurl.com/adaptive-spring-boot

Friday, September 20, 13

Page 45: Adaptive Spring Applications with Profiles and More

REST DESIGN WITH SPRING

An example of using profiles in EC2

Specific Instanceec2-describe-tags --filter "resource-id=i-6e8be600 --filter "key=profile"

Current Instance profile=$(ec2-describe-tags --filter "resource-id=$(ec2-metadata -i | cut -d ' ' -f2)" --filter "key=profile" | cut -f5)

Start Jettyjava -Dprofile=$profile -jar start.jar

java -Dspring.profiles.active=bacon -jar start.jar

Friday, September 20, 13

Page 46: Adaptive Spring Applications with Profiles and More

ADAPTING THE SYSTEM AT CONFIGURATION TIME

The wide world of @Conditional in Spring 4

Friday, September 20, 13

Page 47: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

@Profile are specializations of an annotation called @Conditional.

Sort of.

Friday, September 20, 13

Page 48: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

@Conditional lets you conditionally create beans.

They delegate to Condition instances.

Supports graceful, resilient systems.

Friday, September 20, 13

Page 49: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Spring Boot uses @Conditional to great effect.

Provides a healthy suite of Condition implementations like DatabaseCondition, OnBeanCondition, OnClassCondition, and OnWebApplicationCondition.

You can write your own, too.

Friday, September 20, 13

Page 50: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Demolooking at existing Conditions,writing your own Condition

Friday, September 20, 13

Page 51: Adaptive Spring Applications with Profiles and More

ADAPTING THE SYSTEM AT CONFIGURATION TIME

Refreshing beans with ApplicationContext child contexts

Friday, September 20, 13

Page 52: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

ApplicationContext’s are hierarchical. They nest.

You see this effect when you setup the typical Spring MVC architecture:

ContextLoaderListener

DispatcherServletDispatcherServlet

DispatcherServlet

Friday, September 20, 13

Page 53: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

You can programmatically parent an ApplicationContext, created isolated access to the parent.

You can also isolate and destroy just parts of an ApplicationContext hierarchy, too.

Friday, September 20, 13

Page 54: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Demo“reloading” beans, pt. 1

Friday, September 20, 13

Page 55: Adaptive Spring Applications with Profiles and More

ADAPTING THE SYSTEM AT CONFIGURATION TIME

better decoupling with ApplicationEvents

Friday, September 20, 13

Page 56: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

the Spring ApplicationContext supports a service bus of sorts.

You may publish and receive messages from one component to another using ApplicationEvents.

Friday, September 20, 13

Page 57: Adaptive Spring Applications with Profiles and More

ADAPTING THE SYSTEM AT CONFIGURATION TIME

Refreshing beans with proxies

Friday, September 20, 13

Page 58: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Another approach to refreshing a bean:

1. Use bean proxies to isolate reference holders from the swap.

2. Use ApplicationEvent to trigger the refresh of the bean.

3. Let the client provide the factory method.

Friday, September 20, 13

Page 59: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Demo“reloading” beans, pt. 2

Friday, September 20, 13

Page 60: Adaptive Spring Applications with Profiles and More

ADAPTING THE SYSTEM AT CONFIGURATION TIME

Refreshing beans with the JMX (and proxies)

Friday, September 20, 13

Page 61: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Spring provides the @EnableMBeanExport configuration to easily expose beans through JMX.

@ManagedResourcepublic class JmxDataSourceConfigurationEndpoint implements ApplicationContextAware {

private DataSource dataSource; private ConfigurableEnvironment environment; private ApplicationContext applicationContext;

@ManagedOperation public void updateDataSource(String user, String pw, String url) {

Map<String, Object> map = ... MapPropertySource propertySource = ...

// install the new configuration values environment.getPropertySources().addFirst(propertySource);

// publish the event that our proxies will listen for applicationContext.publishEvent(

new RefreshEvent( this.dataSource)); }}

Friday, September 20, 13

Page 62: Adaptive Spring Applications with Profiles and More

BUILDING ADAPTIVE APPLICATIONS IS HARD

Demo“reloading” beans, pt. 3

Friday, September 20, 13

Page 63: Adaptive Spring Applications with Profiles and More

REST DESIGN WITH SPRING

Any

Questions?@starbuxman | [email protected] | http://slideshare.net/joshlong

@javaclimber | [email protected] | http://www.javaclimber.com

Friday, September 20, 13