免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 1284 | 回复: 0
打印 上一主题 下一主题

The Ioc container4 [复制链接]

论坛徽章:
0
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2007-06-19 16:15 |只看该作者 |倒序浏览
3.5. Customizing the nature of a bean3.5.1. Lifecycle interfaces
The Spring Framework provides several marker interfaces to change the behavior
            of your bean in the container; they include
            InitializingBeanDisposableBean. Implementing these interfaces will
            result in the container calling
            afterPropertiesSet() for the former and
            destroy() and
             for the latter to allow the bean to perform
            certain actions upon initialization and destruction.
Internally, the Spring Framework uses
            BeanPostProcessorBeanPostProcessor yourself. More information about
            this can be found in the section entitled
Section 3.7, “Container extension points”
. implementations to
            process any marker interfaces it can find and call the appropriate
            methods. If you need custom features or other lifecycle behavior Spring
            doesn't offer out-of-the-box, you can implement a
            
All the different lifecycle marker interfaces are described below.
            In one of the appendices, you can find diagram that show how Spring
            manages beans and how those lifecycle features change the nature of your
            beans and how they are managed.
3.5.1.1. Initialization callbacks
Implementing the
                org.springframework.beans.factory.InitializingBean
                interface allows a bean to perform initialization work after all necessary
                properties on the bean are set by the container. The
                InitializingBean interface specifies exactly one
                method:
void afterPropertiesSet() throws Exception;
Generally, the use of the InitializingBean
                interface can be avoided (and is discouraged since it unnecessarily couples
                the code to Spring). A bean definition provides support for a generic
                initialization method to be specified. In the case of XML-based configuration
                metadata, this is done using the 'init-method' attribute.
                For example, the following definition:
public class ExampleBean {
   
    public void init() {
        // do some initialization work
    }
}
Is exactly the same as...
public class AnotherExampleBean implements InitializingBean {
   
    public void afterPropertiesSet() {
        // do some initialization work
    }
}
... but does not couple the code to Spring.
3.5.1.2. Destruction callbacks
Implementing the
                org.springframework.beans.factory.DisposableBeanDisposableBean interface specifies one
                method:
                interface allows a bean to get a callback when the container
                containing it is destroyed. The
void destroy() throws Exception;
Generally, the use of the
                DisposableBean marker interface can be avoided (and
                is discouraged since it unnecessarily couples the code to Spring). A
                bean definition provides support for a generic destroy method to be
                specified. When using XML-based configuration metadata this is done via the
                'destroy-method' attribute on the .
                For example, the following definition:
public class ExampleBean {
    public void cleanup() {
        // do some destruction work (like releasing pooled connections)
    }
}
Is exactly the same as...
public class AnotherExampleBean implements DisposableBean {
    public void destroy() {
        // do some destruction work (like releasing pooled connections)
    }
}
... but does not couple the code to Spring.
3.5.1.2.1. Default initialization & destroy methods
                        When you are writing initialization and destroy method callbacks that do not
                        use the Spring-specific InitializingBean
                        and DisposableBeaninit(),
                        initialize(), dispose(), etc. The
                        names of such lifecycle callback methods are (hopefully!) standardized
                        across a project so that developers on a team all use the same method
                        names and thus ensure some level of consistency.
                     callback interfaces,
                        one (in the experience of this author) typically finds oneself writing
                        methods with names such as
                        The Spring container can now be configured to 'look'
                        for named initialization and destroy callback method names on
                        every bean. This means that you as an application developer
                        can simply write your application classes, use a convention of having an
                        initialization callback called init(), and then
                        (without having to configure each and every bean with, in the case of XML-based
                        configuration, an 'init-method="init"' attribute)
                        be safe in the knowledge that the Spring IoC container will
                        call that method when the bean is being created (and in accordance with the
                        standard lifecycle callback contract described previously).
                    
                        Let's look at an example to make the use of this feature completely clear.
                        For the sake of the example, let us say that one of the coding conventions on a
                        project is that all initialization callback methods are to be named
                        init() and that destroy callback methods are to be called
                        destroy(). This leads to classes like so...
                    
public class DefaultBlogService implements BlogService {
    private BlogDao blogDao;
    public void setBlogDao(BlogDao blogDao) {
        this.blogDao = blogDao;
    }
    // this is (unsurprisingly) the initialization callback method
    public void init() {
        if (this.blogDao == null) {
            throw new IllegalStateException("The [blogDao] property must be set.");
        }
    }
}default-init-method="init">
   
        
   
                        Notice the use of the 'default-init-method' attribute on the
                        top-level  element. The presence of this
                        attribute means that the Spring IoC container will recognize a method called
                        'init' on beans as being the initialization method callback,
                        and when a bean is being created and assembled, if the bean's class has such
                        a method, it will be invoked at the appropriate time.
                    
                        Destroy method callbacks are configured similarly (in XML that is) using the
                        'default-destroy-method' attribute on the top-level
                         element.
                    
                        The use of this feature can save you the (small) housekeeping chore of specifying
                        an initialization and destroy method callback on each and every bean, and it is
                        great for enforcing a consistent naming convention for initialization and destroy
                        method callbacks (and consistency is something that should always be aimed for).
                    
                        Consider the case where you have some existing beans where the
                        underlying classes already have initialization callback methods that
                        are named at variance with the convention. You can
                        always override the default by specifying (in XML that is)
                        the method name using the 'init-method' and
                        'destroy-method' attributes on the
                        element itself.
                    
Finally, please be aware that the Spring container guarantees that
                    a configured initialization callback is called immediately after a bean
                    has been supplied with all of it's dependencies. This means that the
                    initialization callback will be called on the raw bean reference, which
                    means that any AOP interceptors or suchlike that will ultimately
                    be applied to the bean will not yet be in place. A target bean is fully
                    created first, then
                    an AOP proxy (for example) with its interceptor chain is applied. Note that,
                    if the target bean and the proxy are defined separately, your code can even
                    interact to the raw target bean, bypassing the proxy. Hence, it would be very
                    inconsistent to apply the interceptors to the init method, since that would couple
                    the lifecycle of the target bean with its proxy/interceptors, and leave strange
                    semantics when talking to the raw target bean directly.
3.5.1.2.2. Shutting down the Spring IoC container gracefully in non-web applications

Note
This next section does not apply to web applications (in case the title of this section
                        did not make that abundantly clear). Spring's web-based ApplicationContext
                        implementations already have code in place to handle shutting down the Spring
                        IoC container gracefully when the relevant web application is being shutdown.
If you are using Spring's IoC container in a non-web application environment, for
                    example in a rich client desktop environment, and you want the container to shutdown
                    gracefully and call the relevant destroy callbacks on your singleton beans, you will
                    need to register a shutdown hook with the JVM. This is quite easy to do (see below),
                    and will ensure that your Spring IoC container shuts down gracefully and that all
                    resources held by your singletons are released (of course it is still up to you to both
                    configure the destroy callbacks for your singletons and implement such
                    destroy callbacks correctly).
So to register a shutdown hook that enables the graceful shutdown of the relevant
                    Spring IoC container, you simply need to call the
                    registerShutdownHook() method that is declared on the
                    AbstractApplicationContext class. To wit...
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public final class Boot {
    public static void main(final String[] args) throws Exception {
        AbstractApplicationContext ctx
            = new ClassPathXmlApplicationContext(new String []{"beans.xml"});
        // add a shutdown hook for the above context...
        ctx.registerShutdownHook();
        // app runs here...
        // main method exits, hook is called prior to the app shutting down...
    }
}3.5.2. Knowing who you are3.5.2.1.
                    BeanFactoryAware
               
A class which implements the
        org.springframework.beans.factory.BeanFactoryAware
        interface is provided with a reference to the BeanFactory that created
        it, when it is created by that BeanFactory.
        
public interface BeanFactoryAware {
    void setBeanFactory(BeanFactory beanFactory) throws BeansException;
}
            This allows beans to manipulate the BeanFactory
            that created them programmatically, through the BeanFactory
            interface, or by casting the reference to a known subclass of this
            which exposes additional functionality. Primarily this would consist
            of programmatic retrieval of other beans. While there are cases when
            this capability is useful, it should generally be avoided, since it
            couples the code to Spring, and does not follow the Inversion of
            Control style, where collaborators are provided to beans as properties.
        
An alternative option that is equivalent in effect to the
                BeanFactoryAware-based approach is to use the
                org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean.
                (It should be noted that this approach still does not reduce the coupling to Spring,
                but it does not violate the central principle of IoC as much as the
                BeanFactoryAware-based approach.)
The ObjectFactoryCreatingFactoryBean is a
               
FactoryBean
ObjectFactoryCreatingFactoryBean class
                does itself implement the BeanFactoryAware interface;
                what client beans are actually injected with is an instance of the
                ObjectFactory interface. This is a Spring-specific
                interface (and hence there is still no total decoupling from Spring), but clients
                can then use the ObjectFactory's
                getObject()ObjectFactoryBeanFactory to actually
                lookup a bean by name). All that you need to do is supply
                the ObjectFactoryCreatingFactoryBean with the name of the
                bean that is to be looked up. Let's look at an example:
                implementation that returns a reference to an object (factory) that can in turn be used to
                effect a bean lookup. The  method to effect the bean lookup (under the hood the
                 implementation instance that is returned
                simply delegates down to a
package x.y;
public class NewsFeed {
   
    private String news;
    public void setNews(String news) {
        this.news = news;
    }
    public String getNews() {
        return this.toString() + ": '" + news + "'";
    }
}package x.y;
import org.springframework.beans.factory.ObjectFactory;
public class NewsFeedManager {
    private ObjectFactory factory;
    public void setFactory(ObjectFactory factory) {
        this.factory = factory;
    }
    public void printNews() {
        // here is where the lookup is performed; note that there is no
        // need to hardcode the name of the bean that is being looked up...
        NewsFeed news = (NewsFeed) factory.getObject();
        System.out.println(news.getNews());
    }
}
            Find below the XML configuration to wire together the above classes
            using the ObjectFactoryCreatingFactoryBean approach.
        
   
        
            
               
                    
               
            
        
   
   
        
   
            And here is a small driver program to test the fact that new (prototype)
            instances of the newsFeed bean are actually being returned for
            each call to the injected ObjectFactory inside the
            NewsFeedManager's printNews() method.
        
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import x.y.NewsFeedManager;
public class Main {
    public static void main(String[] args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
        NewsFeedManager manager = (NewsFeedManager) ctx.getBean("newsFeedManager");
        manager.printNews();
        manager.printNews();
    }
}
            The output from running the above program will look like so (results will of course vary
            on your machine).
        
x.y.NewsFeed@1292d26: '... that's fit to print!'
x.y.NewsFeed@5329c5: '... that's fit to print!'3.5.2.2. BeanNameAware
If a bean implements the
                org.springframework.beans.factory.BeanNameAware
                interface and is deployed in a BeanFactory, the
                BeanFactory will call the bean through this
                interface to inform the bean of the id it was deployed
                under. The callback will be invoked after population of normal bean properties
                but before an initialization callback like InitializingBean's
                afterPropertiesSet or a custom init-method.
3.6. Bean definition inheritance
A bean definition potentially contains a large amount of
        configuration information, including container specific information (for example
        initialization method, static factory method name, and so forth) and constructor
        arguments and property values. A child bean definition is a bean
        definition that inherits configuration data from a parent definition. It
        is then able to override some values, or add others, as needed. Using
        parent and child bean definitions can potentially save a lot of typing.
        Effectively, this is a form of templating.
When working with a BeanFactory programmatically, child bean
        definitions are represented by the ChildBeanDefinition
        class. Most users will never work with them on this level, instead
        configuring bean definitions declaratively in something like the
        XmlBeanFactory. When using XML-based configuration metadata a child bean
        definition is indicated simply by using the 'parent'
        attribute, specifying the parent bean as the value of this attribute.
  
  
parent="inheritedTestBean" init-method="initialize">
   
  
  
A child bean definition will use the bean class from the parent
        definition if none is specified, but can also override it. In the latter
        case, the child bean class must be compatible with the parent, that is it
        must accept the parent's property values.
A child bean definition will inherit constructor argument values,
        property values and method overrides from the parent, with the option to
        add new values. If any init-method, destroy-method and/or static
        factory method settings are specified, they will override the corresponding parent
        settings.
The remaining settings will always be taken
        from the child definition: depends on,
        autowire mode, dependency check,
        singleton, scope,
                lazy init.
Note that in the example above, we have explicitly marked the parent
        bean definition as abstract by using the abstract
        attribute. In the case that the parent definition does not specify a
        class, and so explicitly marking the parent bean definition as
        abstract is required:
   
   
  
  1 from the parent bean definition-->
The parent bean cannot get instantiated on its own since it is
        incomplete, and it is also explicitly marked as abstract.
        When a definition is defined to be abstract like this,
        it is usable only as a pure template bean definition that will serve as a
        parent definition for child definitions. Trying to use such an
        abstract parent bean on its own (by referring to it as
        a ref property of another bean, or doing an explicit
        getBean() call with the parent bean id), will
        result in an error. Similarly, the container's internal
        preInstantiateSingletons() method will completely
        ignore bean definitions which are defined as abstract.

Note
ApplicationContexts (but not
            BeanFactories) will by default pre-instantiate
            all singletons. Therefore it is important (at least for singleton beans)
            that if you have a (parent) bean definition which you intend to use only
            as a template, and this definition specifies a class, you must make sure
            to set the 'abstract' attribute to 'true',
            otherwise the application context will actually (attempt to) pre-instantiate
            the abstract bean.
3.7. Container extension points
The IoC component of the Spring Framework has been designed for extension.
        There is typically no need for an application developer to subclass any of the various
        BeanFactory or ApplicationContext
        implementation classes. The Spring IoC container can be infinitely extended by
        plugging in implementations of special integration interfaces. The next few sections are
        devoted to detailing all of these various integration interfaces.
3.7.1. Customizing beans using BeanPostProcessors
The first extension point that we will look at is the
            BeanPostProcessor interface. This interface defines
            a number of callback methods that you as an application
            developer can implement in order to provide your own (or override the containers default)
            instantiation logic, dependency-resolution logic, and so forth. If you want to do
            some custom logic after the Spring container has finished instantiating, configuring
            and otherwise initializing a bean, you can plug in one or more
            BeanPostProcessor implementations.
You can configure multiple BeanPostProcessors if you wish.
            You can control the order in which these BeanPostProcessors
            execute by setting the 'order' property (you can only set this property
            if the BeanPostProcessor
            implements the Ordered interface; if you write your own
            BeanPostProcessor you should consider implementing the
            OrderedBeanPostProcessor and Ordered
            interfaces for more details. interface too); consult the Javadocs for the
            

Note
BeanPostProcessors operate on bean (or object)
                instances; that is to say, the Spring IoC container will
                have instantiated a bean instance for you, and then
                BeanPostProcessors get a chance to do their stuff.
If you want to change the actual bean definition (that is the recipe that
                defines the bean), then you rather need to use a
                BeanFactoryPostProcessor
Section 3.7.2, “Customizing configuration metadata with BeanFactoryPostProcessors”
. (described below in the
                section entitled
Also, BeanPostProcessors are scoped per-container.
                This is only relevant if you are using container hierarchies. If you define a
                BeanPostProcessor in one container, it will
                only do its stuff on the beans in that container. Beans that
                are defined in another container will not be post-processed by
                BeanPostProcessors in another container, even if both containers
                are part of the same hierarchy.
The org.springframework.beans.factory.config.BeanPostProcessorbefore any container
            initialization methods (such as afterPropertiesSet
            interface consists of exactly two callback methods. When such a class is
            registered as a post-processor with the container (see below for how this registration
            is effected), for each bean instance that is created by the container, the post-processor
            will get a callback from the container both  and any declared
            init method) are called, and also afterwards. The post-processor is free to do what it
            wishes with the bean instance, including ignoring the callback completely. A bean
            post-processor will typically check for marker interfaces, or do something such as wrap
            a bean with a proxy; some of the Spring AOP infrastructure classes are implemented as bean
            post-processors and they do this proxy-wrapping logic.
It is important to know that a BeanFactory treats bean
            post-processors slightly differently than an ApplicationContext.
            An ApplicationContext will automatically detect
            any beans which are defined in the configuration metadata which is supplied to it that
            implement the BeanPostProcessor interface, and register them
            as post-processors, to be then called appropriately by the container on bean creation. Nothing
            else needs to be done other than deploying the post-processors in a similar fashion to any
            other bean. On the other hand, when using a BeanFactory
            implementation, bean post-processors explicitly have to be registered, with code like this:
ConfigurableBeanFactory factory = new XmlBeanFactory(...);
            
// now register any needed BeanPostProcessor instances
MyBeanPostProcessor postProcessor = new MyBeanPostProcessor();
factory.addBeanPostProcessor(postProcessor);
// now start using the factory
This explicit registration step is not convenient, and this is one of the
            reasons why the various ApplicationContext
            implementations are preferred above plain BeanFactory
            implementations in the vast majority of Spring-backed applications, especially
            when using BeanPostProcessors.

BeanPostProcessors and AOP auto-proxying
Classes that implement the BeanPostProcessorspecial, and so they are treated differently
                                by the container. All BeanPostProcessors
                                and their directly referenced beans will be instantiated
                                on startup, as part of the special startup phase of the
                                ApplicationContext, then
                                all those BeanPostProcessors will be registered
                                in a sorted fashion - and applied to all further beans. Since AOP
                                auto-proxying is implemented as a BeanPostProcessor
                                itself, no BeanPostProcessors or directly
                                referenced beans are eligible for auto-proxying (and thus will not have
                                aspects 'woven' into them.
                                interface are
For any such bean, you should see an info log message:
                                “Bean 'foo' is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)”.
Find below some examples of how to write, register, and use
            BeanPostProcessors in the context of an
            ApplicationContext.
3.7.1.1. Example: Hello World, BeanPostProcessor-style
This first example is hardly compelling, but serves to illustrate basic
                usage. All we are going to do is code a custom BeanPostProcessortoString()
                method of each bean as it is created by the container and prints the resulting
                string to the system console. Yes, it is not hugely useful, but serves to get
                the basic concepts across before we move into the second example which
                is actually useful.
                implementation that simply invokes the
Find below the custom BeanPostProcessor
                implementation class definition:
package scripting;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.BeansException;
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {
    // simply return the instantiated bean as-is
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean; // we could potentially return any object reference here...
    }
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("Bean '" + beanName + "' created : " + bean.toString());
        return bean;
    }
}
   
         
   
   
    BeanPostProcessor implementation will output the fact to the system console
     -->
   
Notice how the InstantiationTracingBeanPostProcessor is
                simply defined; it doesn't even have a name, and because it is a bean it can be
                dependency injected just like any other bean. (The above configuration also just so
                happens to define a bean that is backed by a Groovy script. The Spring 2.0 dynamic
                language support is detailed in the chapter entitled
               
Chapter 24, Dynamic language support
.)
Find below a small driver script to exercise the above code and
                configuration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.scripting.Messenger;
public final class Boot {
    public static void main(final String[] args) throws Exception {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("scripting/beans.xml");
        Messenger messenger = (Messenger) ctx.getBean("messenger");
        System.out.println(messenger);
    }
}
The output of executing the above program will be (something like) this:
Bean 'messenger' created : org.springframework.scripting.groovy.GroovyMessenger@272961
org.springframework.scripting.groovy.GroovyMessenger@2729613.7.1.2. Example: The RequiredAnnotationBeanPostProcessor
Using marker interfaces or annotations in conjunction with a custom
                BeanPostProcessor implementation is a common
                means of extending the Spring IoC container. This next example is a bit of
                a cop-out, in that you are directed to the section entitled
               
Section 25.3.1, “@Required”
BeanPostProcessor which demonstrates the usage of a
                custom  implementation that
                ships with the Spring distribution which ensures that JavaBean properties on
                beans that are marked with an (arbitrary) annotation are actually (configured to
                be) dependency-injected with a value.
3.7.2. Customizing configuration metadata with BeanFactoryPostProcessors
The next extension point that we will look at is the
            org.springframework.beans.factory.config.BeanFactoryPostProcessor.
            The semantics of this interface are similar to the BeanPostProcessor,
            with one major difference. BeanFactoryPostProcessors operate on; that is to say,
            the Spring IoC container will allow BeanFactoryPostProcessors to read the
            configuration metadata and potentially change it before the
            container has actually instantied any other beans.
You can configure multiple BeanFactoryPostProcessors if you wish.
            You can control the order in which these BeanFactoryPostProcessors'order' property (you can only set this property
            if the BeanFactoryPostProcessor
            implements the Ordered interface; if you write your own
            BeanFactoryPostProcessor you should consider
            implementing the Ordered interface too); consult
            the Javadocs for the BeanFactoryPostProcessor
            and Ordered interfaces for more details.
            execute by setting the

Note
If you want to change the actual bean instances
                (the objects that are created from the configuration metadata), then
                you rather need to use a BeanPostProcessor
                (described above in the section entitled
               
Section 3.7.1, “Customizing beans using BeanPostProcessors”
.
Also, BeanFactoryPostProcessors are scoped
                per-container. This is only relevant if you are
                using container hierarchies. If you define a
                BeanFactoryPostProcessor in one container,
                it will only do its stuff on the bean definitions in
                that container. Bean definitions in another container will not be
                post-processed by BeanFactoryPostProcessors in another
                container, even if both containers are part of the same hierarchy.
A bean factory post-processor is executed manually (in the case of a
            BeanFactory) or automatically (in the case of an
            ApplicationContext) to apply changes of
            some sort to the configuration metadata that defines a container. Spring
            includes a number of pre-existing bean factory post-processors, such as
            PropertyResourceConfigurer and
            PropertyPlaceholderConfigurer, both described below,
            and BeanNameAutoProxyCreator, which is very useful for wrapping
            other beans transactionally or with any other kind of proxy, as described
            later in this manual. The BeanFactoryPostProcessor
            can be used to add custom property editors.
In a BeanFactory, the process of applying a
            BeanFactoryPostProcessor is manual, and will be
            similar to this:
XmlBeanFactory factory = new XmlBeanFactory(new FileSystemResource("beans.xml"));
// bring in some property values from a Properties file
PropertyPlaceholderConfigurer cfg = new PropertyPlaceholderConfigurer();
cfg.setLocation(new FileSystemResource("jdbc.properties"));
// now actually do the replacement
cfg.postProcessBeanFactory(factory);
This explicit registration step is not convenient, and this is one of the
            reasons why the various ApplicationContext
            implementations are preferred above plain BeanFactory
            implementations in the vast majority of Spring-backed applications, especially
            when using BeanFactoryPostProcessors.
An ApplicationContext will detect any beans which
            are deployed into it which implement the BeanFactoryPostProcessor
            interface, and automatically use them as bean factory post-processors, at the appropriate
            time. Nothing else needs to be done other than deploying these post-processor in a similar
            fashion to any other bean.

Note
Just as in the case of BeanPostProcessors, you typically
                don't want to have BeanFactoryPostProcessors
                marked as being lazily-initialized. If they are marked as such, then the Spring
                container will never instantiate them, and thus they won't get a chance
                to apply their custom logic. If you are using the
                'default-lazy-init'BeanFactoryPostProcessor bean definitions with
                'lazy-init="false"'.
                 attribute on the declaration of your
                 element, be sure to mark your various
               
3.7.2.1. Example: the PropertyPlaceholderConfigurer
The PropertyPlaceholderConfigurer
                                is used to externalize property values from a
                                BeanFactory definition, into another
                separate file in the standard Java Properties format.
                This is useful to allow the person deploying an application to customize
                                enviroment-specific properties (for example database URLs, usernames and passwords), without the
                complexity or risk of modifying the main XML definition file or files for the
                container.
Consider the following XML-based configuration metadata fragment, where a
                DataSource with placeholder values is defined. We
                will configure some properties from an external Properties
                file, and at runtime, we will apply a
                PropertyPlaceholderConfigurer to the metadata which will
                replace some properties of the datasource:
   
        classpath:com/foo/jdbc.properties
   
    ${jdbc.driverClassName}"/>
    ${jdbc.url}"/>
    ${jdbc.username}"/>
    ${jdbc.password}"/>
The actual values come from another file in the standard Java
                Properties format:
jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root
The PropertyPlaceholderConfigurer doesn't only
                                look for properties in the Properties file you
                                specify, but also checks against the Java System
                                properties if it cannot find a property you are trying to use. This
                                behavior can be customized by setting the systemPropertiesModenever override and
                                one to let it override only if the property cannot be found in the
                                properties file specified. Please consult the Javadoc for the
                                PropertiesPlaceholderConfigurer for more information.
                                property of the configurer. It has three values, one to tell the configurer
                                to always override, one to let it

Class name substitution
The PropertyPlaceholderConfigurer
                                        can be used to substitute class names, which is sometimes useful
                                        when you have to pick a particular implementation class at runtime.
                                        For example:
   
        classpath:com/foo/strategy.properties
   
   
        custom.strategy.class=com.foo.DefaultStrategy
   
If the class is unable to be resolved at runtime to a valid class,
                                        resolution of the the bean will fail once it is about to be created
                                        (which is during the preInstantiateSingletons()ApplicationContext for a
                                        non-lazy-init bean.)
                                        phase of an
3.7.2.2. Example: the PropertyOverrideConfigurer
The PropertyOverrideConfigurer, another bean
                factory post-processor, is similar to the
                PropertyPlaceholderConfigurer, but in contrast to the
                latter, the original definitions can have default values or no values at
                all for bean properties. If an overriding Properties file
                does not have an entry for a certain bean property, the default context definition
                is used.
Note that the bean factory definition is not
                aware of being overridden, so it is not immediately obvious when looking
                at the XML definition file that the override configurer is being used.
                In case that there are multiple PropertyOverrideConfigurer
                instances that define different values for the same bean property, the last one
                will win (due to the overriding mechanism).
Properties file configuration lines are expected to be in the format:
beanName.property=value
An example properties file might look like this:
dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb
This example file would be usable against a container definition
                which contains a bean called dataSource,
                which has driver and url
                properties.
Note that compound property names are also supported, as long as
                every component of the path except the final property being overridden is
                already non-null (presumably initialized by the constructors). In this
                example...
foo.fred.bob.sammy=123
... the sammy property of the bob property
                of the fred property of the foo
                bean is being set to the scalar value 123.
3.7.3. Customizing instantiation logic using FactoryBeans
The org.springframework.beans.factory.FactoryBean
            interface is to be implemented by objects that are themselves
            factories.
The FactoryBean interface is a point of pluggability
            into the Spring IoC containers instantiation logic. If you have some complex
            initialization code that is better expressed in Java as opposed to a (potentially)
            verbose amount of XML, you can create your own FactoryBean,
            write the complex initialization inside that class, and then plug your custom
            FactoryBean into the container.
The FactoryBean interface provides three methods:

  • Object getObject(): has to return an
                        instance of the object this factory creates. The instance can
                        possibly be shared (depending on whether this factory returns
                        singletons or prototypes).

  • boolean isSingleton(): has to return
                        true if this FactoryBeanfalse otherwise
                        returns singletons,

  • Class getObjectType(): has to return
                        either the object type returned by the
                        getObject() method or null
                        if the type isn't known in advance

    The FactoryBean concept and interface
                is used in a number of places within the Spring Framework; at the time of writing
                there are over 50 implementations of the FactoryBean
                interface that ship with Spring itself.
    Finally, there is sometimes a need to ask a container for an actual
                FactoryBean instance itself, not the bean it produces.
                This may be achieved by prepending the bean id with '&'
                (sans quotes) when calling the getBean method of
                the BeanFactory (including
                ApplicationContext). So for a given
                FactoryBean with an id of myBean,
                invoking getBean("myBean") on the container will return the
                product of the FactoryBean, but invoking
                getBean("&myBean") will return the
                FactoryBean instance itself.
    3.8. The ApplicationContext
    While the beans package provides basic
            functionality for managing and manipulating beans, often in a programmatic
            way, the context package adds
            
    ApplicationContext
    ,
            which enhances BeanFactory functionality in a more
            framework-oriented style. Many users will use
            ApplicationContext in a completely declarative fashion,
            not even having to create it manually, but instead relying on support classes such as
            ContextLoader to automatically start an ApplicationContext as part of the
            normal startup process of a J2EE web-app. Of course, it is still possible
            to programmatically create an ApplicationContext.
    The basis for the context package is the
            ApplicationContext interface, located in the
            org.springframework.context package. Deriving from the
            BeanFactory interface, it provides all the functionality of
            BeanFactory. To allow working in a more framework-oriented
            fashion, using layering and hierarchical contexts, the context package also provides the
            following functionality:

  • MessageSource, providing access to
                        messages in i18n-style

  • Access to resources, such as URLs and files

  • Event propagation to beans implementing
                        the ApplicationListener interface

  • Loading of multiple (hierarchical)
                        contexts, allowing each to be focused on one particular
                        layer, for example the web layer of an application

    As the ApplicationContext includes all functionality of the
            BeanFactory, it is generally recommended that it be used over the
            BeanFactory, except for a few limited situations such as perhaps in an
            Applet, where memory consumption might be critical, and a few extra
            kilobytes might make a difference. The following sections describe
            functionality that ApplicationContext adds to basic BeanFactory
            capabilities.
    3.8.1. Internationalization using MessageSources
    The ApplicationContext interface extends an interface called
                MessageSource, and therefore provides messaging (i18n
                or internationalization) functionality. Together with the
                HierarchicalMessageSource, capable of resolving
                hierarchical messages, these are the basic interfaces Spring provides to
                do message resolution. Let's quickly review the methods defined there:

  • String getMessage(String code, Object[] args,
                            String default, Locale loc): the basic method used to
                            retrieve a message from the MessageSource. When no message is
                            found for the specified locale, the default message is used. Any
                            arguments passed in are used as replacement values, using the
                            MessageFormat functionality provided by the
                            standard library.

  • String getMessage(String code, Object[] args,
                            Locale loc): essentially the same as the previous
                            method, but with one difference: no default message can be
                            specified; if the message cannot be found, a
                            NoSuchMessageException is thrown.

  • String getMessage(MessageSourceResolvable
                                                    resolvable, Locale locale): all properties used in the
                                                    methods above are also wrapped in a class named
                                                    MessageSourceResolvable, which you can use via
                                                    this method.

                                    When an ApplicationContext gets loaded, it automatically searches
                                    for a MessageSource bean defined in the context. The bean has to have
                                    the name messageSource. If such a bean is found, all
                                    calls to the methods described above will be delegated to the message
                                    source that was found. If no message source was found, the
                                    ApplicationContext attempts to see if it has a parent containing a bean
                                    with the same name. If so, it uses that bean as the MessageSource. If it
                                    can't find any source for messages, an empty
                                    StaticMessageSource will be instantiated in order to
                                    be able to accept calls to the methods defined above.
                           
                                    Spring currently provides two MessageSource
                                    implementations. These are the
                                    ResourceBundleMessageSource and the
                                    StaticMessageSource. Both implement
                                    NestingMessageSource in order to do nested messaging.
                                    The StaticMessageSource is hardly ever used but provides programmatic
                                    ways to add messages to the source. The ResourceBundleMessageSource is
                                    more interesting and is the one we will provide an example for:
          
      
       
          
            format
            exceptions
            windows
          
       
      
    This assumes you have three resource bundles defined on your
          classpath called format,
          exceptions and windows. Using the
          JDK standard way of resolving messages through ResourceBundles, any
          request to resolve a message will be handled. For the purposes of the example,
          lets assume the contents of two of the above resource bundle files are...
    # in 'format.properties'
    message=Alligators rock!# in 'exceptions.properties'
    argument.required=The '{0}' argument is required.
    Some (admittedly trivial) driver code to exercise the
            MessageSourceApplicationContextMessageSource implementations and so can be cast to the
            MessageSource interface. functionality can be found below. Remember
            that all  implementations are also
            
    public static void main(String[] args) {
        MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
        String message = resources.getMessage("message", null, "Default", null);
        System.out.println(message);
    }
    The resulting output from the above program will be...
    Alligators rock!
    So to summarize, the MessageSource is defined in a file
            called 'beans.xml' (this file exists at the root of your classpath).
            The 'messageSource' bean definition refers to a number
            of resource bundles via it's basenames property; the three files
            that are passed in the list to the basenames property exist as files
            at the root of your classpath (and are called
            format.properties, exceptions.properties,
            and windows.properties respectively).
    Lets look at another example, and this time we will look at passing arguments
            to the message lookup; these arguments will be converted into strings and inserted
            into placeholders in the lookup message. This is perhaps best explained with an
            example:
        MessageSource is being used in a web application -->
       
            
       
       
        MessageSource into this POJO -->
       
            
       
    public class Example {
        private MessageSource messages;
        public void setMessages(MessageSource messages) {
            this.messages = messages;
        }
        public void execute() {
            String message = this.messages.getMessage("argument.required",
                new Object [] {"userDao"}, "Required", null);
            System.out.println(message);
        }
    }
    The resulting output from the invocation of the execute()
                method will be...
    The 'userDao' argument is required.
    With regard to internationalization (i18n), Spring's various
            MessageResource implementations follow the same locale resolution
            and fallback rules as the standard JDK ResourceBundle. In short, and continuing with
            the example 'messageSource' defined previously, if you want to resolve
            messages against the British (en-GB) locale, you would create files called
            format_en_GB.properties, exceptions_en_GB.properties,
            and windows_en_GB.properties respectively.
    Locale resolution is typically going to be managed by the surrounding environment
            of the application. For the purpose of this example though, we'll just manually
            specify the locale that we want to resolve our (British) messages against.
    # in 'exceptions_en_GB.properties'
    argument.required=Ebagum lad, the '{0}' argument is required, I say, required.public static void main(final String[] args) {
        MessageSource resources = new ClassPathXmlApplicationContext("beans.xml");
        String message = resources.getMessage("argument.required",
            new Object [] {"userDao"}, "Required", Locale.UK);
        System.out.println(message);
    }
    The resulting output from the running of the above program will be...
    Ebagum lad, the 'userDao' argument is required, I say, required.
    The MessageSourceAware interface can also be used to acquire
                a reference to any MessageSource that has been defined. Any bean
                that is defined in an ApplicationContext that implements the
                MessageSourceAware interface will be injected with the
                application context's MessageSource when it (the bean) is being
                created and configured.
    3.8.2. Events
    Event handling in the ApplicationContext is provided
                            through the ApplicationEvent class and
                            ApplicationListener interface. If a bean which
                            implements the ApplicationListener interface is
                            deployed into the context, every time an ApplicationEvent
                            gets published to the ApplicationContext, that
                            bean will be notified. Essentially, this is the standard Observer
                            design pattern. Spring provides        three standard events:
    Table 3.5. Built-in Events
    EventExplanationContextRefreshedEvent
    Published when the
                                    ApplicationContext is
                                    initialized or refreshed. Initialized here means that all
                                    beans are loaded, singletons are pre-instantiated and the
                                    ApplicationContext is ready
                                    for use.
    ContextClosedEvent
    Published when the ApplicationContext is closed,
                                    using the close() method on the
                                    ApplicationContext. Closed here means
                                    that singleton beans (only!) are destroyed.
    RequestHandledEvent
    A web-specific event telling all beans that a HTTP
                                    request has been serviced (this will be published
                                    after the request has been finished).
                                    Note that this event is only applicable for web applications
                                    using Spring's DispatcherServlet.
    Implementing custom events can be done as well. Simply call the
                            publishEvent() method on the ApplicationContext,
                            specifying a parameter which is an instance of your custom event class
                            implementing ApplicationEvent. Event listeners receive events
                            synchronously. This means the publishEvent() method blocks until all
                            listeners have finished processing the event (it is possible to supply
                            an alternate event publishing strategy via a
                            ApplicationEventMulticaster implementation).
                            Furthermore, when a listener receives an event it operates inside the transaction context of
                            the publisher, if a transaction context is available.
    Let's look at an example. First, the ApplicationContext:
      
       
          black@list.org
          white@list.org
          john@doe.org
       
      
      
    Now, let's look at the actual classes:
    public class EmailBean implements ApplicationContextAware {
        private List blackList;
            private ApplicationContext ctx;
        public void setBlackList(List blackList) {
            this.blackList = blackList;
        }
        public void setApplicationContext(ApplicationContext ctx) {
            this.ctx = ctx;
        }
        public void sendEmail(String address, String text) {
            if (blackList.contains(address)) {
                BlackListEvent evt = new BlackListEvent(address, text);
                ctx.publishEvent(evt);
                return;
            }
            // send email...
        }
    }public class BlackListNotifier implements ApplicationListener {
        private String notificationAddress;
       
        public void setNotificationAddress(String notificationAddress) {
            this.notificationAddress = notificationAddress;
        }
        public void onApplicationEvent(ApplicationEvent evt) {
            if (evt instanceof BlackListEvent) {
                // notify appropriate person...
            }
        }
    }
    Of course, this particular example could probably be
                            implemented in better ways (perhaps by using AOP features), but it
                            should be sufficient to illustrate the basic event mechanism.
    3.8.3. Convenient access to low-level resources
    For optimal usage and understanding of application contexts, users
                            should generally familiarize themselves with Spring's
                            Resource abstraction, as described
                            in the chapter entitled
    Chapter 4, Resources
    .
                                    An application context is a ResourceLoader,
                                    able to be used to load Resources. A
                                    Resource is essentially a
                                    java.net.URL on steroids (in fact, it just wraps and
                                    uses a URL where appropriate), which can be used to obtain low-level
                                    resources from almost any location in a transparent fashion, including
                                    from the classpath, a filesystem location, anywhere describable with a
                                    standard URL, and some other variations. If the resource location string
                                    is a simple path without any special prefixes, where those resources
                                    come from is specific and appropriate to the actual application context
                                    type.
                           
    A bean deployed into the application context may implement the
                            special marker interface, ResourceLoaderAware, to be
                            automatically called back at initialization time with the application
                            context itself passed in as the ResourceLoader.
                                    A bean may also expose properties of type
                                    Resource, to be used to access static resources, and
                                    expect that they will be injected into it like any other properties. The
                                    person deploying the bean may specify those Resource
                                    properties as simple String paths, and rely on a special JavaBean
                                    PropertyEditor that is automatically registered
                                    by the context, to convert those text strings to actual Resource
                                    objects.
                           
    The location path or paths supplied to an ApplicationContextClassPathXmlApplicationContext treats a simple location path as a
                            classpath location), but may also be used with special prefixes to force
                            loading of definitions from the classpath or a URL, regardless of the
                            actual context type.
                            constructor are actually resource strings, and in simple form are
                            treated appropriately to the specific context implementation (
                           
    3.8.4. Convenient ApplicationContext instantiation for web applications
    As opposed to the BeanFactory, which will
                            often be created programmatically, ApplicationContext
                            instances can be created declaratively using for example a
                            ContextLoader. Of course you can also create
                            ApplicationContext instances programmatically
                            using one of the ApplicationContext implementations.
                            First, let's examine the ContextLoader interface
                            and its implementations.
    The ContextLoader interface has two
                implementations: the ContextLoaderListener and the
                            ContextLoaderServlet. They both have the same
                            functionality but differ in that the listener version cannot be used in Servlet
                            2.2 compatible containers. Since the Servlet 2.4 specification, servlet context
                            listeners are required to execute immediately after the servlet context for the
                            web application has been created and is available to service the first request
                            (and also when the servlet context is about to be shut down): as such a
                            servlet context listener is an ideal place to initialize the Spring
                            ApplicationContext. It is up to you
                            as to which one you use, but all things being equal you should probably
                            prefer ContextLoaderListener; for more information on
                            compatibility, have a look at the Javadoc for the
                            ContextLoaderServlet.
    You can register an ApplicationContext using the
                            ContextLoaderListener as follows:
      contextConfigLocation
      /WEB-INF/daoContext.xml /WEB-INF/applicationContext.xml
      org.springframework.web.context.ContextLoaderListener
    ContextLoaderServlet instead of the above listener
      context
      org.springframework.web.context.ContextLoaderServlet
      1
    -->
    The listener inspects the
                            contextConfigLocation parameter. If it doesn't exist,
                            it'll use /WEB-INF/applicationContext.xml as a default.
                            When it does exist, it'll separate the String using
                            predefined delimiters (comma, semi-colon and whitespace) and use the values as
                            locations where application contexts will be searched for. The
                            ContextLoaderServlet can be used instead of the
                            ContextLoaderListener. The servlet will use the
                            'contextConfigLocation' parameter just as the listener does.
    3.9. Glue code and the evil singleton
    The majority of the code inside an application is best written in a
                    DI style, where that code is served out of a Spring IoC container, has its own
                    dependencies supplied by the container when it is created, and is
                    completely unaware of the container. However, for the small glue layers of
                    code that are sometimes needed to tie other code together, there is
                    sometimes a need for singleton (or quasi-singleton) style access to a
                    Spring IoC container. For example,
                    third party code may try to construct new objects directly (Class.forName()
                    style), without the ability to force it to get these objects out of a
                    Spring IoC container. If the object constructed by the
                    third party code is just a small stub or proxy, which then uses a singleton style access to a
                    Spring IoC container to get a real object to delegate to, then inversion of control has
                    still been achieved for the majority of the code (the object coming out of the
                    container); thus most code is still        unaware of the container or how it is accessed, and
                    remains uncoupled from other code, with all ensuing benefits. EJBs may also use this stub/proxy
                    approach to delegate to a plain Java implementation object, coming out of
                    a Spring IoC container. While the Spring IoC container itself ideally does not have to be a
                    singleton, it may be unrealistic in terms of memory usage or initialization times (when
                    using beans in the Spring IoC container such as a Hibernate
                    SessionFactory) for each bean to use its own, non-singleton
                    Spring IoC container.
    As another example, in a complex J2EE apps with multiple layers
            (various JAR files, EJBs, and WAR files packaged as an EAR),
            with each layer having its own Spring IoC container definition
            (effectively forming a hierarchy), the preferred approach when
            there is only one web-app (WAR) in the top hierarchy is to simply
            create one composite Spring IoC container from the multiple XML definition
            files from each layer. All of the various Spring IoC container implementations
            may be constructed from multiple definition files in this fashion.
            However, if there are multiple sibling web-applications at the root
            of the hierarchy, it is problematic to create a
            Spring IoC container for each web-application
            which consists of mostly identical bean definitions from lower layers,
            as there may be issues due to increased memory usage, issues with
            creating multiple copies of beans which take a long time to initialize
            (e.g. a Hibernate SessionFactory), and
            possible issues due to side-effects. As an alternative, classes such as
            
    ContextSingletonBeanFactoryLocator
            or
            
    SingletonBeanFactoryLocator
            may be used to demand-load multiple hierarchical (that is one container is the parent of
            another) Spring IoC container instances in a singleton fashion,
            which may then be used as the parents of the web-application Spring IoC
            container instances. The result is that bean definitions for lower layers are
            loaded only as needed, and loaded only once.
    3.9.1. Using the Singleton-helper classes
    You can see a detailed example of their usage in
                
    SingletonBeanFactoryLocator
                and
                
    ContextSingletonBeanFactoryLocator
                by viewing their respective Javadocs.
    As mentioned in the
    chapter on EJBs
    , the
                Spring convenience base classes for EJBs normally use a non-singleton
                BeanFactoryLocatorSingletonBeanFactoryLocator
                and ContextSingletonBeanFactoryLocator if there is
                a need. implementation, which is
                easily replaced by the use of
                   
                   
                   

    本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/24141/showart_324455.html
  • 您需要登录后才可以回帖 登录 | 注册

    本版积分规则 发表回复

      

    北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
    未成年举报专区
    中国互联网协会会员  联系我们:huangweiwei@itpub.net
    感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

    清除 Cookies - ChinaUnix - Archiver - WAP - TOP