KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > springframework > beans > factory > support > CglibSubclassingInstantiationStrategy


1 /*
2  * Copyright 2002-2007 the original author or authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16
17 package org.springframework.beans.factory.support;
18
19 import java.lang.reflect.Constructor JavaDoc;
20 import java.lang.reflect.Method JavaDoc;
21
22 import net.sf.cglib.proxy.Callback;
23 import net.sf.cglib.proxy.CallbackFilter;
24 import net.sf.cglib.proxy.Enhancer;
25 import net.sf.cglib.proxy.MethodInterceptor;
26 import net.sf.cglib.proxy.MethodProxy;
27 import net.sf.cglib.proxy.NoOp;
28 import org.apache.commons.logging.Log;
29 import org.apache.commons.logging.LogFactory;
30
31 import org.springframework.beans.factory.BeanFactory;
32
33 /**
34  * Default object instantiation strategy for use in BeanFactories.
35  * Uses CGLIB to generate subclasses dynamically if methods need to be
36  * overridden by the container, to implement Method Injection.
37  *
38  * <p>Using Method Injection features requires CGLIB on the classpath.
39  * However, the core IoC container will still run without CGLIB being available.
40  *
41  * @author Rod Johnson
42  * @since 1.1
43  */

44 public class CglibSubclassingInstantiationStrategy extends SimpleInstantiationStrategy {
45
46     /**
47      * Index in the CGLIB callback array for passthrough behavior,
48      * in which case the subclass won't override the original class.
49      */

50     private static final int PASSTHROUGH = 0;
51
52     /**
53      * Index in the CGLIB callback array for a method that should
54      * be overridden to provide method lookup.
55      */

56     private static final int LOOKUP_OVERRIDE = 1;
57     
58     /**
59      * Index in the CGLIB callback array for a method that should
60      * be overridden using generic Methodreplacer functionality.
61      */

62     private static final int METHOD_REPLACER = 2;
63
64
65     protected Object JavaDoc instantiateWithMethodInjection(
66             RootBeanDefinition beanDefinition, String JavaDoc beanName, BeanFactory owner) {
67
68         // Must generate CGLIB subclass.
69
return new CglibSubclassCreator(beanDefinition, owner).instantiate(null, null);
70     }
71
72     protected Object JavaDoc instantiateWithMethodInjection(
73             RootBeanDefinition beanDefinition, String JavaDoc beanName, BeanFactory owner,
74             Constructor JavaDoc ctor, Object JavaDoc[] args) {
75
76         return new CglibSubclassCreator(beanDefinition, owner).instantiate(ctor, args);
77     }
78
79
80     /**
81      * An inner class so we don't have a CGLIB dependency in core.
82      */

83     private static class CglibSubclassCreator {
84
85         private static final Log logger = LogFactory.getLog(CglibSubclassCreator.class);
86
87         private final RootBeanDefinition beanDefinition;
88
89         private final BeanFactory owner;
90
91         public CglibSubclassCreator(RootBeanDefinition beanDefinition, BeanFactory owner) {
92             this.beanDefinition = beanDefinition;
93             this.owner = owner;
94         }
95
96         /**
97          * Create a new instance of a dynamically generated subclasses implementing the
98          * required lookups.
99          * @param ctor constructor to use. If this is <code>null</code>, use the
100          * no-arg constructor (no parameterization, or Setter Injection)
101          * @param args arguments to use for the constructor.
102          * Ignored if the ctor parameter is <code>null</code>.
103          * @return new instance of the dynamically generated class
104          */

105         public Object JavaDoc instantiate(Constructor JavaDoc ctor, Object JavaDoc[] args) {
106             Enhancer enhancer = new Enhancer();
107             enhancer.setSuperclass(this.beanDefinition.getBeanClass());
108             enhancer.setCallbackFilter(new CallbackFilterImpl());
109             enhancer.setCallbacks(new Callback[] {
110                     NoOp.INSTANCE,
111                     new LookupOverrideMethodInterceptor(),
112                     new ReplaceOverrideMethodInterceptor()
113             });
114
115             return (ctor == null) ?
116                     enhancer.create() :
117                     enhancer.create(ctor.getParameterTypes(), args);
118         }
119
120
121         /**
122          * Class providing hashCode and equals methods required by CGLIB to
123          * ensure that CGLIB doesn't generate a distinct class per bean.
124          * Identity is based on class and bean definition.
125          */

126         private class CglibIdentitySupport {
127             /**
128              * Exposed for equals method to allow access to enclosing class field
129              */

130             protected RootBeanDefinition getBeanDefinition() {
131                 return beanDefinition;
132             }
133             
134             public int hashCode() {
135                 return beanDefinition.hashCode();
136             }
137             
138             public boolean equals(Object JavaDoc other) {
139                 return (other.getClass() == getClass()) &&
140                         ((CglibIdentitySupport) other).getBeanDefinition() == beanDefinition;
141             }
142         }
143
144
145         /**
146          * CGLIB MethodInterceptor to override methods, replacing them with an
147          * implementation that returns a bean looked up in the container.
148          */

149         private class LookupOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
150
151             public Object JavaDoc intercept(Object JavaDoc obj, Method JavaDoc method, Object JavaDoc[] args, MethodProxy mp) throws Throwable JavaDoc {
152                 // Cast is safe, as CallbackFilter filters are used selectively.
153
LookupOverride lo = (LookupOverride) beanDefinition.getMethodOverrides().getOverride(method);
154                 return owner.getBean(lo.getBeanName());
155             }
156         }
157
158
159         /**
160          * CGLIB MethodInterceptor to override methods, replacing them with a call
161          * to a generic MethodReplacer.
162          */

163         private class ReplaceOverrideMethodInterceptor extends CglibIdentitySupport implements MethodInterceptor {
164
165             public Object JavaDoc intercept(Object JavaDoc obj, Method JavaDoc method, Object JavaDoc[] args, MethodProxy mp) throws Throwable JavaDoc {
166                 ReplaceOverride ro = (ReplaceOverride) beanDefinition.getMethodOverrides().getOverride(method);
167                 // TODO could cache if a singleton for minor performance optimization
168
MethodReplacer mr = (MethodReplacer) owner.getBean(ro.getMethodReplacerBeanName());
169                 return mr.reimplement(obj, method, args);
170             }
171         }
172
173
174         /**
175          * CGLIB object to filter method interception behavior.
176          */

177         private class CallbackFilterImpl extends CglibIdentitySupport implements CallbackFilter {
178             
179             public int accept(Method JavaDoc method) {
180                 MethodOverride methodOverride = beanDefinition.getMethodOverrides().getOverride(method);
181                 if (logger.isTraceEnabled()) {
182                     logger.trace("Override for '" + method.getName() + "' is [" + methodOverride + "]");
183                 }
184                 if (methodOverride == null) {
185                     return PASSTHROUGH;
186                 }
187                 else if (methodOverride instanceof LookupOverride) {
188                     return LOOKUP_OVERRIDE;
189                 }
190                 else if (methodOverride instanceof ReplaceOverride) {
191                     return METHOD_REPLACER;
192                 }
193                 throw new UnsupportedOperationException JavaDoc(
194                         "Unexpected MethodOverride subclass: " + methodOverride.getClass().getName());
195             }
196         }
197     }
198
199 }
200
Popular Tags