|
20 | 20 | import java.util.Collections; |
21 | 21 | import java.util.List; |
22 | 22 |
|
23 | | -import javax.annotation.PostConstruct; |
24 | 23 | import javax.sql.DataSource; |
25 | 24 |
|
26 | 25 | import org.apache.commons.logging.Log; |
27 | 26 | import org.apache.commons.logging.LogFactory; |
28 | 27 |
|
29 | 28 | import org.springframework.boot.context.config.ResourceNotFoundException; |
30 | 29 | import org.springframework.boot.jdbc.DataSourceBuilder; |
31 | | -import org.springframework.context.ApplicationContext; |
32 | | -import org.springframework.context.ApplicationListener; |
| 30 | +import org.springframework.core.io.DefaultResourceLoader; |
33 | 31 | import org.springframework.core.io.Resource; |
| 32 | +import org.springframework.core.io.ResourceLoader; |
34 | 33 | import org.springframework.jdbc.config.SortedResourcesFactoryBean; |
35 | 34 | import org.springframework.jdbc.datasource.init.DatabasePopulatorUtils; |
36 | 35 | import org.springframework.jdbc.datasource.init.ResourceDatabasePopulator; |
37 | 36 | import org.springframework.util.StringUtils; |
38 | 37 |
|
39 | 38 | /** |
40 | | - * Bean to handle {@link DataSource} initialization by running {@literal schema-*.sql} on |
41 | | - * {@link PostConstruct} and {@literal data-*.sql} SQL scripts on a |
42 | | - * {@link DataSourceInitializedEvent}. |
| 39 | + * Initialize a {@link DataSource} based on a matching {@link DataSourceProperties} |
| 40 | + * config. |
43 | 41 | * |
44 | 42 | * @author Dave Syer |
45 | 43 | * @author Phillip Webb |
46 | 44 | * @author Eddú Meléndez |
47 | 45 | * @author Stephane Nicoll |
48 | 46 | * @author Kazuki Shimizu |
49 | | - * @see DataSourceAutoConfiguration |
50 | 47 | */ |
51 | | -class DataSourceInitializer implements ApplicationListener<DataSourceInitializedEvent> { |
| 48 | +class DataSourceInitializer { |
52 | 49 |
|
53 | 50 | private static final Log logger = LogFactory.getLog(DataSourceInitializer.class); |
54 | 51 |
|
55 | | - private final DataSourceProperties properties; |
| 52 | + private final DataSource dataSource; |
56 | 53 |
|
57 | | - private final ApplicationContext applicationContext; |
| 54 | + private final DataSourceProperties properties; |
58 | 55 |
|
59 | | - private DataSource dataSource; |
| 56 | + private final ResourceLoader resourceLoader; |
| 57 | + |
| 58 | + /** |
| 59 | + * Create a new instance with the {@link DataSource} to initialize and its matching |
| 60 | + * {@link DataSourceProperties configuration}. |
| 61 | + * @param dataSource the datasource to initialize |
| 62 | + * @param properties the matching configuration |
| 63 | + * @param resourceLoader the resource loader to use (can be null) |
| 64 | + */ |
| 65 | + DataSourceInitializer(DataSource dataSource, DataSourceProperties properties, |
| 66 | + ResourceLoader resourceLoader) { |
| 67 | + this.dataSource = dataSource; |
| 68 | + this.properties = properties; |
| 69 | + this.resourceLoader = (resourceLoader != null ? resourceLoader |
| 70 | + : new DefaultResourceLoader()); |
| 71 | + } |
60 | 72 |
|
61 | | - private boolean initialized = false; |
| 73 | + /** |
| 74 | + * Create a new instance with the {@link DataSource} to initialize and its matching |
| 75 | + * {@link DataSourceProperties configuration}. |
| 76 | + * @param dataSource the datasource to initialize |
| 77 | + * @param properties the matching configuration |
| 78 | + */ |
| 79 | + DataSourceInitializer(DataSource dataSource, DataSourceProperties properties) { |
| 80 | + this(dataSource, properties, null); |
| 81 | + } |
62 | 82 |
|
63 | | - DataSourceInitializer(DataSourceProperties properties, |
64 | | - ApplicationContext applicationContext) { |
65 | | - this.properties = properties; |
66 | | - this.applicationContext = applicationContext; |
| 83 | + public DataSource getDataSource() { |
| 84 | + return this.dataSource; |
67 | 85 | } |
68 | 86 |
|
69 | | - @PostConstruct |
70 | | - public void init() { |
| 87 | + /** |
| 88 | + * Create the schema if necessary. |
| 89 | + * @return {@code true} if the schema was created |
| 90 | + * @see DataSourceProperties#getSchema() |
| 91 | + */ |
| 92 | + public boolean createSchema() { |
71 | 93 | if (!this.properties.isInitialize()) { |
72 | 94 | logger.debug("Initialization disabled (not running DDL scripts)"); |
73 | | - return; |
74 | | - } |
75 | | - if (this.applicationContext.getBeanNamesForType(DataSource.class, false, |
76 | | - false).length > 0) { |
77 | | - this.dataSource = this.applicationContext.getBean(DataSource.class); |
| 95 | + return false; |
78 | 96 | } |
79 | | - if (this.dataSource == null) { |
80 | | - logger.debug("No DataSource found so not initializing"); |
81 | | - return; |
82 | | - } |
83 | | - runSchemaScripts(); |
84 | | - } |
85 | | - |
86 | | - private void runSchemaScripts() { |
87 | 97 | List<Resource> scripts = getScripts("spring.datasource.schema", |
88 | 98 | this.properties.getSchema(), "schema"); |
89 | 99 | if (!scripts.isEmpty()) { |
90 | 100 | String username = this.properties.getSchemaUsername(); |
91 | 101 | String password = this.properties.getSchemaPassword(); |
92 | 102 | runScripts(scripts, username, password); |
93 | | - try { |
94 | | - this.applicationContext |
95 | | - .publishEvent(new DataSourceInitializedEvent(this.dataSource)); |
96 | | - // The listener might not be registered yet, so don't rely on it. |
97 | | - if (!this.initialized) { |
98 | | - runDataScripts(); |
99 | | - this.initialized = true; |
100 | | - } |
101 | | - } |
102 | | - catch (IllegalStateException ex) { |
103 | | - logger.warn("Could not send event to complete DataSource initialization (" |
104 | | - + ex.getMessage() + ")"); |
105 | | - } |
106 | 103 | } |
| 104 | + return !scripts.isEmpty(); |
107 | 105 | } |
108 | 106 |
|
109 | | - @Override |
110 | | - public void onApplicationEvent(DataSourceInitializedEvent event) { |
| 107 | + /** |
| 108 | + * Initialize the schema if necessary. |
| 109 | + * @see DataSourceProperties#getData() |
| 110 | + */ |
| 111 | + public void initSchema() { |
111 | 112 | if (!this.properties.isInitialize()) { |
112 | 113 | logger.debug("Initialization disabled (not running data scripts)"); |
113 | 114 | return; |
114 | 115 | } |
115 | | - // NOTE the event can happen more than once and |
116 | | - // the event datasource is not used here |
117 | | - if (!this.initialized) { |
118 | | - runDataScripts(); |
119 | | - this.initialized = true; |
120 | | - } |
121 | | - } |
122 | | - |
123 | | - private void runDataScripts() { |
124 | 116 | List<Resource> scripts = getScripts("spring.datasource.data", |
125 | 117 | this.properties.getData(), "data"); |
126 | | - String username = this.properties.getDataUsername(); |
127 | | - String password = this.properties.getDataPassword(); |
128 | | - runScripts(scripts, username, password); |
| 118 | + if (!scripts.isEmpty()) { |
| 119 | + String username = this.properties.getDataUsername(); |
| 120 | + String password = this.properties.getDataPassword(); |
| 121 | + runScripts(scripts, username, password); |
| 122 | + |
| 123 | + } |
129 | 124 | } |
130 | 125 |
|
131 | 126 | private List<Resource> getScripts(String propertyName, List<String> resources, |
@@ -159,7 +154,7 @@ else if (validate) { |
159 | 154 | private Resource[] doGetResources(String location) { |
160 | 155 | try { |
161 | 156 | SortedResourcesFactoryBean factory = new SortedResourcesFactoryBean( |
162 | | - this.applicationContext, Collections.singletonList(location)); |
| 157 | + this.resourceLoader, Collections.singletonList(location)); |
163 | 158 | factory.afterPropertiesSet(); |
164 | 159 | return factory.getObject(); |
165 | 160 | } |
|
0 commit comments