1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.springframework.beans.factory.support;
18
19 import java.lang.reflect.Constructor;
20 import java.lang.reflect.Method;
21
22 import org.apache.commons.logging.Log;
23 import org.apache.commons.logging.LogFactory;
24
25 import org.springframework.beans.BeanInstantiationException;
26 import org.springframework.beans.BeanUtils;
27 import org.springframework.beans.factory.BeanFactory;
28 import org.springframework.cglib.core.SpringNamingPolicy;
29 import org.springframework.cglib.proxy.Callback;
30 import org.springframework.cglib.proxy.CallbackFilter;
31 import org.springframework.cglib.proxy.Enhancer;
32 import org.springframework.cglib.proxy.Factory;
33 import org.springframework.cglib.proxy.MethodInterceptor;
34 import org.springframework.cglib.proxy.MethodProxy;
35 import org.springframework.cglib.proxy.NoOp;
36 import org.springframework.util.StringUtils;
37
38
39
40
41
42
43
44
45
46
47
48
49 public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
50
51
52
53
54
55 private static final int PASSTHROUGH = 0;
56
57
58
59
60
61 private static final int LOOKUP_OVERRIDE = 1;
62
63
64
65
66
67 private static final int METHOD_REPLACER = 2;
68
69
70 @Override
71 protected Object instantiateWithMethodInjection(RootBeanDefinition bd, String beanName, BeanFactory owner) {
72 return instantiateWithMethodInjection(bd, beanName, owner, null);
73 }
74
75 @Override
76 protected Object instantiateWithMethodInjection(RootBeanDefinition bd, String beanName, BeanFactory owner,
77 Constructor<?> ctor, Object... args) {
78
79
80 return new CglibSubclassCreator(bd, owner).instantiate(ctor, args);
81 }
82
83
84
85
86
87
88 private static class CglibSubclassCreator {
89
90 private static final Class<?>[] CALLBACK_TYPES = new Class<?>[]
91 {NoOp.class, LookupOverrideMethodInterceptor.class, ReplaceOverrideMethodInterceptor.class};
92
93 private final RootBeanDefinition beanDefinition;
94
95 private final BeanFactory owner;
96
97 CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) {
98 this.beanDefinition = beanDefinition;
99 this.owner = owner;
100 }
101
102
103
104
105
106
107
108
109
110
111 public Object instantiate(Constructor<?> ctor, Object... args) {
112 Class<?> subclass = createEnhancedSubclass(this.beanDefinition);
113 Object instance;
114 if (ctor == null) {
115 instance = BeanUtils.instantiate(subclass);
116 }
117 else {
118 try {
119 Constructor<?> enhancedSubclassConstructor = subclass.getConstructor(ctor.getParameterTypes());
120 instance = enhancedSubclassConstructor.newInstance(args);
121 }
122 catch (Exception ex) {
123 throw new BeanInstantiationException(this.beanDefinition.getBeanClass(),
124 "Failed to invoke constructor for CGLIB enhanced subclass [" + subclass.getName() + "]", ex);
125 }
126 }
127
128
129 Factory factory = (Factory) instance;
130 factory.setCallbacks(new Callback[] {NoOp.INSTANCE,
131 new LookupOverrideMethodInterceptor(this.beanDefinition, this.owner),
132 new ReplaceOverrideMethodInterceptor(this.beanDefinition, this.owner)});
133 return instance;
134 }
135
136
137
138
139
140 private Class<?> createEnhancedSubclass(RootBeanDefinition beanDefinition) {
141 Enhancer enhancer = new Enhancer();
142 enhancer.setSuperclass(beanDefinition.getBeanClass());
143 enhancer.setNamingPolicy(SpringNamingPolicy.INSTANCE);
144 enhancer.setCallbackFilter(new MethodOverrideCallbackFilter(beanDefinition));
145 enhancer.setCallbackTypes(CALLBACK_TYPES);
146 return enhancer.createClass();
147 }
148 }
149
150
151
152
153
154
155
156 private static class CglibIdentitySupport {
157
158 private final RootBeanDefinition beanDefinition;
159
160 public CglibIdentitySupport(RootBeanDefinition beanDefinition) {
161 this.beanDefinition = beanDefinition;
162 }
163
164 public RootBeanDefinition getBeanDefinition() {
165 return this.beanDefinition;
166 }
167
168 @Override
169 public boolean equals(Object other) {
170 return (getClass().equals(other.getClass()) &&
171 this.beanDefinition.equals(((CglibIdentitySupport) other).beanDefinition));
172 }
173
174 @Override
175 public int hashCode() {
176 return this.beanDefinition.hashCode();
177 }
178 }
179
180
181
182
183
184 private static class MethodOverrideCallbackFilter extends CglibIdentitySupport implements CallbackFilter {
185
186 private static final Log logger = LogFactory.getLog(MethodOverrideCallbackFilter.class);
187
188 public MethodOverrideCallbackFilter(RootBeanDefinition beanDefinition) {
189 super(beanDefinition);
190 }
191
192 @Override
193 public int accept(Method method) {
194 MethodOverride methodOverride = getBeanDefinition().getMethodOverrides().getOverride(method);
195 if (logger.isTraceEnabled()) {
196 logger.trace("Override for '" + method.getName() + "' is [" + methodOverride + "]");
197 }
198 if (methodOverride == null) {
199 return PASSTHROUGH;
200 }
201 else if (methodOverride instanceof LookupOverride) {
202 return LOOKUP_OVERRIDE;
203 }
204 else if (methodOverride instanceof ReplaceOverride) {
205 return METHOD_REPLACER;
206 }
207 throw new UnsupportedOperationException("Unexpected MethodOverride subclass: " +
208 methodOverride.getClass().getName());
209 }
210 }
211
212
213
214
215
216
217 private static class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
218
219 private final BeanFactory owner;
220
221 public LookupOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
222 super(beanDefinition);
223 this.owner = owner;
224 }
225
226 @Override
227 public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
228
229 LookupOverride lo = (LookupOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
230 Object[] argsToUse = (args.length > 0 ? args : null);
231 if (StringUtils.hasText(lo.getBeanName())) {
232 return this.owner.getBean(lo.getBeanName(), argsToUse);
233 }
234 else {
235 return this.owner.getBean(method.getReturnType(), argsToUse);
236 }
237 }
238 }
239
240
241
242
243
244
245 private static class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
246
247 private final BeanFactory owner;
248
249 public ReplaceOverrideMethodInterceptor(RootBeanDefinition beanDefinition, BeanFactory owner) {
250 super(beanDefinition);
251 this.owner = owner;
252 }
253
254 @Override
255 public Object intercept(Object obj, Method method, Object[] args, MethodProxy mp) throws Throwable {
256 ReplaceOverride ro = (ReplaceOverride) getBeanDefinition().getMethodOverrides().getOverride(method);
257
258 MethodReplacer mr = this.owner.getBean(ro.getMethodReplacerBeanName(), MethodReplacer.class);
259 return mr.reimplement(obj, method, args);
260 }
261 }
262
263 }