-
Notifications
You must be signed in to change notification settings - Fork 3
/
JarHelsingBeanFactoryPostProcessor.java
130 lines (109 loc) · 5.01 KB
/
JarHelsingBeanFactoryPostProcessor.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
package com.github.springjarhelsing;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.access.BootstrapException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.support.GenericXmlApplicationContext;
import java.net.MalformedURLException;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collection;
import java.util.List;
public class JarHelsingBeanFactoryPostProcessor implements BeanDefinitionRegistryPostProcessor, DisposableBean {
private Collection<String> resourceLocations;
private Collection<String> overridenClasspathUrls;
private JarHelsingClassLoader jarHelsingClassLoader;
private GenericXmlApplicationContext subcontext;
public void setResourceLocations(Collection<String> resourceLocations) {
assertNotNull("resourceLocations", resourceLocations);
assertNotEmpty("resourceLocations", resourceLocations);
this.resourceLocations = resourceLocations;
}
public void setOverridenClasspathUrls(List<String> overridenClasspathUrls) {
assertNotNull("overridenClasspathUrls", overridenClasspathUrls);
assertNotEmpty("overridenClasspathUrls", overridenClasspathUrls);
this.overridenClasspathUrls = overridenClasspathUrls;
}
@Override
public void destroy() throws Exception {
try {
if (subcontext != null) {
subcontext.close();
}
} finally {
if (jarHelsingClassLoader != null) {
jarHelsingClassLoader.close();
}
}
}
@Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
// do nothing
}
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
assertConfigured("overridenClasspathUrls", overridenClasspathUrls);
assertConfigured("resourceLocations", resourceLocations);
ClassLoader previousContextClassLoader = getContextClassLoader();
try {
ClassLoader parentClassLoader = getClass().getClassLoader();
this.jarHelsingClassLoader = new JarHelsingClassLoader(overridenClasspathUrls, parentClassLoader);
setContextClassloader(jarHelsingClassLoader);
this.subcontext = createSubcontext(resourceLocations);
exportSingletons(configurableListableBeanFactory, subcontext);
} finally {
setContextClassloader(previousContextClassLoader);
}
}
private void exportSingletons(ConfigurableListableBeanFactory configurableListableBeanFactory, GenericXmlApplicationContext subcontext) {
for (String beanName: subcontext.getBeanDefinitionNames()) {
if (subcontext.getBeanDefinition(beanName).isSingleton()) {
Object singleton = subcontext.getBean(beanName);
configurableListableBeanFactory.registerSingleton(beanName, singleton);
}
}
}
private static GenericXmlApplicationContext createSubcontext(Collection<String> resourceLocations) {
GenericXmlApplicationContext subcontext = new GenericXmlApplicationContext();
subcontext.load(resourceLocations.toArray(new String[0]));
subcontext.refresh();
return subcontext;
}
private ClassLoader getContextClassLoader() {
PrivilegedAction<ClassLoader> action = new PrivilegedAction<ClassLoader>() {
@Override
public ClassLoader run() {
return Thread.currentThread().getContextClassLoader();
}
};
return AccessController.doPrivileged(action);
}
private void setContextClassloader(final ClassLoader previousContextClassloader) {
PrivilegedAction<Void> action = new PrivilegedAction<Void>() {
@Override
public Void run() {
Thread.currentThread().setContextClassLoader(previousContextClassloader);
return null;
}
};
AccessController.doPrivileged(action);
}
private static void assertNotNull(String name, Collection<String> collection) {
if (collection == null) {
throw new IllegalArgumentException(name + " can not be null");
}
}
private static void assertNotEmpty(String name, Collection<String> collection) {
if (collection.isEmpty()) {
throw new IllegalArgumentException(name + " can not be empty");
}
}
private static void assertConfigured(String name, Collection<String> collection) {
if (collection == null) {
throw new IllegalStateException(name + " should be configured");
}
}
}