bean 订阅
EJB是Enterprise Java Bean的缩写,一个Bean扮演着应用程序素材的角色。它包含有一个functional interface,一个life-cycle interface,以及一个实现它所支援的商业方法的类别。 展开全文
EJB是Enterprise Java Bean的缩写,一个Bean扮演着应用程序素材的角色。它包含有一个functional interface,一个life-cycle interface,以及一个实现它所支援的商业方法的类别。
信息
缩    写
Bean
定    义
描述Java的软件组件模型
类    型
应用程序素材的角色
目    的
将可以重复使用的软件代码打包
应用范围
应用于服务器的部件
外文名
Enterprise Java Bean
Bean定义
JavaBean是描述Java的软件组件模型,有点类似于Microsoft的COM组件概念。在Java模型中,通过JavaBean可以无限扩充Java程序的功能,通过JavaBean的组合可以快速的生成新的应用程序。对于程序员来说,最好的一点就是JavaBean可以实现代码的重复利用,另外对于程序的易维护性等等也有很重大的意义。比如说一个购物车程序,要实现购物车中添加一件商品这样的功能,就可以写一个购物车操作的JavaBean,建立一个public的AddItem成员方法,前台Jsp文件里面直接调用这个方法来实现。如果后来又考虑添加商品的时候需要判断库存是否有货物,没有货物不得购买,在这个时候我们就可以直接修改JavaBean的AddItem方法,加入处理语句来实现,这样就完全不用修改前台jsp程序了。一个简单的JavaBeanFirstJavaBean.javaimportjava.io.*;public class FirstJavaBean {private String FirstProperty = new String("");public FirstJavaBean() {}public String getFirstProperty() {return FirstProperty;}public void setFirstProperty(String value) {FirstProperty = value;}public static void main(String[] args){System.out.println("My First JavaBean!");}}如果运行这个程序,就会出现下面的结果:My First JavaBean!这是一个很典型的JavaBean的代表,简单地解释一下,FirstProperty是其中的一个属性(Property),外部通过get/set方法可以对这个属性进行操作,如果您写过VB的class的话,对这个就再也熟悉不过了。Main方法是为了测试程序用的,写JavaBean可以先不必加入到Jsp程序中调用,而直接用main方法来进行调试,调试好以后就可以在Jsp程序中调用了。
收起全文
精华内容
下载资源
问答
  • Bean

    千次阅读 2016-05-17 16:22:24
    spring bean

    Bean

    首先要熟悉两个概念:

    配置元数据:元数据配置包含很多配置信息, 包括构造函数参数注入, 对象属性值, 和容器相关的信息比如初始化方法, 工厂方法等等.

    bean: 是一个被实例化,组装,并通过 Spring IoC 容器所管理的对象。

    这些 bean 是由用容器提供的配置元数据创建的,例如,之前在 XML 的表单中的定义。

    这里写图片描述

    bean 定义包含称为配置元数据的信息,下述容器也需要知道配置元数据:

    • 如何创建一个 bean
    • bean 的生命周期的详细信息
    • bean 的依赖关系
    属性 描述
    class 这个属性是强制性的,并且指定用来创建 bean 的 bean 类。
    name 这个属性指定唯一的 bean 标识符。在基于 XML 的配置元数据中,你可以使用 ID 和/或 name 属性来指定 bean 标识符。
    scope 这个属性指定由特定的 bean 定义创建的对象的作用域,它将会在 bean 作用域的章节中进行讨论。
    constructor-arg 它是用来注入依赖关系的,并会在接下来的章节中进行讨论。
    properties 它是用来注入依赖关系的,并会在接下来的章节中进行讨论。
    autowiring mode 它是用来注入依赖关系的,并会在接下来的章节中进行讨论。
    lazy-initialization mode 延迟初始化的 bean 告诉 IoC 容器在它第一次被请求时,而不是在启动时去创建一个 bean 实例。
    initialization 方法 在 bean 的所有必需的属性被容器设置之后,调用回调方法。它将会在 bean 的生命周期章节中进行讨论。
    destruction 方法 当包含该 bean 的容器被销毁时,使用回调方法。它将会在 bean 的生命周期章节中进行讨论。

    bean的作用域

    Spring 框架支持以下五个作用域。

    作用域 描述
    singleton 该作用域将 bean 的定义的限制在每一个 Spring IoC 容器中的一个单一实例(默认)。
    prototype 该作用域将单一 bean 的定义限制在任意数量的对象实例。
    request 该作用域将 bean 的定义限制为 HTTP 请求。只在 web-aware Spring ApplicationContext 的上下文中有效。
    session 该作用域将 bean 的定义限制为 HTTP 会话。 只在web-aware Spring ApplicationContext的上下文中有效。
    global-session 该作用域将 bean 的定义限制为全局 HTTP 会话。只在 web-aware Spring ApplicationContext 的上下文中有效。

    singleton 作用域:

    如果作用域设置为 singleton,那么 Spring IoC 容器刚好创建一个由该 bean 定义的对象的实例。该单一实例将存储在这种单例 bean 的高速缓存中,以及针对该 bean 的所有后续的请求和引用都返回缓存对象。

    默认作用域是始终是 singleton,但是当仅仅需要 bean 的一个实例时,你可以在 bean 的配置文件中设置作用域的属性为 singleton。
    案例:

    package com.yangjun;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    import org.springframework.context.support.FileSystemXmlApplicationContext;
    
    public class MainApp {
        public static void main(String[] args) {        
            ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
            HelloWorld objA = (HelloWorld) context.getBean("helloWorld");
            objA.setMessage("I'm object A");
            objA.getMessage();
            HelloWorld objB = (HelloWorld) context.getBean("helloWorld");
            objB.getMessage();
        }
    }

    然后修改Beans.xml文件

        <bean id="helloWorld" class="com.yangjun.HelloWorld" scope="singleton">
            <property name="message" value="杨峻!" />
        </bean>

    控制台输出信息为:

    这里写图片描述

    prototype 作用域

    如果作用域设置为 prototype,那么每次特定的 bean 发出请求时 Spring IoC 容器就创建对象的新的 Bean 实例。一般说来,满状态的 bean 使用 prototype 作用域和没有状态的 bean 使用 singleton 作用域。

    为了定义 prototype 作用域,你可以在 bean 的配置文件中设置作用域的属性为 prototype。
    修改Beans.xml文件

        <bean id="helloWorld" class="com.yangjun.HelloWorld" scope="prototype">
            <property name="message" value="杨峻!" />
        </bean>

    控制台输出信息为:
    这里写图片描述

    bean的实例化方式

    Spring的实例化Bean有三种方式:

    • 使用类构造器直接实例化
    • 使用静态工厂的方法实例化
    • 使用实例工厂方法实例化

    XML

    <?xml version="1.0" encoding="UTF-8"?>  
    <beans xmlns="http://www.springframework.org/schema/beans" 
            xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
            xmlns:context="http://www.springframework.org/schema/context" 
            xmlns:tx="http://www.springframework.org/schema/tx" 
            xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd  
                    http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd  
                    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.5.xsd">  
            <!-- 使用类构造器直接实例化 -->    
            <bean id="userBean1" class="com.yangjun.spring.implbean.UserBean" />  
            <!-- 使用静态工厂的方法实例化 -->  
            <bean id="userBean2" class="com.yangjun.spring.factory.BeanFactory" factory-method="UserBeanService" />  
            <!-- 使用实例工厂方法实例化 -->  
            <bean id="factory" class="com.yangjun.spring.factory.BeanFactory" />  
            <bean id="userBean3" factory-bean="factory" factory-method="getUserBeanService" />  
    </beans>  

    bean的生命周期

    Bean 的生命周期从Spring容器着手实例化Bean开始,直到最终销毁Bean,这当中经过了许多关键点,每个关键点都涉及特定方法的调用,可以将这些方法大致划分为4类:

    • Bean自身的方法:如调用Bean构造函数,实例化Bean,调用Setter设置Bean的属性值以及通过xml中bean的init-method和destroy-method所指定的方法;

    • Bean级生命周期接口方法:如BeanNameAware、BeanFactoryAware、InitializationBean和DisposableBean,这些接口方法由Bean类直接实现;

    • 容器级生命周期接口方法:由InstantiationAwareBeanPostProcessor和BeanPostProcessor这两个接口实现,一般称他们的实现类为”后处理器“。

    • 工厂后处理器接口方法:这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。

    Bean自身的方法:

    先说两个简单的生命周期回调方法,为了定义安装和拆卸一个 bean,我们需要声明 init-method和 destroy-method。在实例化 bean 时,立即调用init-method方法方法。同样,只有从容器中移除 bean之后,才能调用destroy-method方法。

    初始化回调
    org.springframework.beans.factory.InitializingBean 接口指定一个单一的方法:

    void afterPropertiesSet() throws Exception;

    因此,可以简单地在 afterPropertiesSet() 方法中实现上述接口和初始化工作,如下所示:

    package com.yangjun.bean;
    
    import org.springframework.beans.factory.InitializingBean;
    
    public class HelloWorld implements InitializingBean {
        private String message;
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public void getMessage() {
            System.out.println("Your Message : " + message);
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            // TODO Auto-generated method stub
            System.out.println("正在准备");
        }
    
    }

    在基于 XML 的配置元数据的情况下,你可以使用 init-method 属性来指定带有 void 无参数方法的名称。例如:

        <bean id="helloWorld" class="com.yangjun.bean.HelloWorld"
            init-method="init" >
            <property name="message" value="杨峻!" />
        </bean>

    下面是类的定义:

    package com.yangjun.bean;
    
    import org.springframework.beans.factory.InitializingBean;
    
    public class HelloWorld implements InitializingBean {
        private String message;
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public void getMessage() {
            System.out.println("Your Message : " + message);
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            // TODO Auto-generated method stub
            System.out.println("正在准备");
        }
    
        public void init() {
            System.out.println("正在生成");
        }
    
    }

    销毁回调

    org.springframework.beans.factory.DisposableBean 接口指定一个单一的方法:

    void destroy() throws Exception;

    因此,你可以简单地实现上述接口并且结束工作可以在 destroy() 方法中执行,如下所示:

    package com.yangjun.bean;
    
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    
    public class HelloWorld implements InitializingBean, DisposableBean {
        private String message;
    
        public void setMessage(String message) {
            this.message = message;
        }
    
        public void getMessage() {
            System.out.println("Your Message : " + message);
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            // TODO Auto-generated method stub
            System.out.println("正在准备");
        }
    
        public void init() {
            System.out.println("正在生成");
        }
    
        public void destroy() {
            // TODO Auto-generated method stub
            System.out.println("正在销毁");
        }
    
    }
    

    在基于 XML 的配置元数据的情况下,你可以使用 destroy-method 属性来指定带有 void 无参数方法的名称。例如:

        <bean id="helloWorld" class="com.yangjun.bean.HelloWorld"
            init-method="init" destroy-method="destroy">
            <property name="message" value="杨峻!" />
        </bean>

    需要注意的是当bean的作用域定义为prototype的时候是不会被spring销毁的,只能等待垃圾回收机制销毁

    修改主程序MainApp.java

            AbstractApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
            HelloWorld objA = (HelloWorld) context.getBean("helloWorld");
            objA.getMessage();
            context.registerShutdownHook();

    运行MainApp.java

    控制台输出:

    这里写图片描述

    如果有多个bean的初始化和销毁的方法名都是一样的,可以在beans里面声明default-init-method 和 default-destroy-method来配置

    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
        default-init-method="init" 
        default-destroy-method="destroy">
    
       <bean id="..." class="...">
           <!-- collaborators and configuration for this bean go here -->
       </bean>
    
    </beans>

    Bean的后处理器:

    容器级生命周期接口方法是由InstantiationAwareBeanPostProcessor和BeanPostProcessor这两个接口实现,一般称他们的实现类为“后处理器”

    后处理器可以用于提供自己的实例化逻辑,依赖解析逻辑等。
    也可以在 Spring 容器通过插入一个或多个 BeanPostProcessor 的实现,来完成经过实例化,配置和初始化一个bean之后的一些自定义逻辑回调方法。

    可以配置多个 BeanPostProcessor接口,然后通过设置 BeanPostProcessor 实现的 Ordered 接口提供的 order 属性来控制这些 BeanPostProcessor 接口的执行顺序。

    BeanPostProcessor 可以对 bean(或对象)实例进行操作,这意味着 Spring IoC 容器实例化一个 bean 实例,然后 BeanPostProcessor 接口进行它们的工作。

    ApplicationContext 会自动检测由 BeanPostProcessor 接口的实现定义的 bean,注册这些 bean 为后置处理器,然后通过在容器中创建 bean,在适当的时候调用它。

    在上面的例子的基础之上,创建一个BeanPostProcessor后处理器:

    package com.yangjun.postprocessor;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class BPP01 implements BeanPostProcessor {
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            // TODO Auto-generated method stub
            System.out.println("BeforeInitialization : " + beanName);
            return bean;
            // return null;
        }
    
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            // TODO Auto-generated method stub
            System.out.println("AfterInitialization : " + beanName);
            return bean;
            // return null;
        }
    
    }
    

    配置Bean.xml

        <bean class="com.yangjun.postprocessor.BPP01" />

    运行主程序:
    这里写图片描述

    剩下的我还在研究

    其他例子和我的理解:

    实现各种生命周期控制访问的Car

    package com.yangjun.bean;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.BeanFactoryAware;
    import org.springframework.beans.factory.BeanNameAware;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.beans.factory.InitializingBean;
    
    public class Car implements BeanFactoryAware, BeanNameAware, InitializingBean, DisposableBean {
        private String brand;
        private String color;
        private int maxSpeed;
        private BeanFactory beanFactory;
        private String beanName;
    
        public String getColor() {
            return color;
        }
        public void setColor(String color) {
            this.color = color;
        }
        public int getMaxSpeed() {
            return maxSpeed;
        }
        public void setMaxSpeed(int maxSpeed) {
            this.maxSpeed = maxSpeed;
        }
        public String getBrand() {
            return brand;
        }
        public BeanFactory getBeanFactory() {
            return beanFactory;
        }
        public String getBeanName() {
            return beanName;
        }
        // 管理Bean生命周期的接口
        public Car() {
            System.out.println("调用Car构造函数");
        }
        public void setBrand(String brand) {
            System.out.println("调用setBrand()设置属性");
            this.brand = brand;
        }
        // BeanNameAware接口方法
        public void setBeanName(String beanName) {
            System.out.println("调用BeanNameAware.setBeanName()");
            this.beanName = beanName;
        }
        // BeanFactoryAware接口方法
        public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
            System.out.println("调用BeanFactoryAware.setBeanFactory()");
            this.beanFactory = beanFactory;
        }
    
        // initializingBean接口方法
        public void afterPropertiesSet() throws Exception {
            System.out.println("调用InitializingBean.afterPropertiesSet()");
        }
        // 通过<bean>的init-method属性指定的初始化方法
        public void myInit() {
            System.out.println("调用inti-method所指定的myInit(),将maxSpeed设置为240.");
            this.maxSpeed = 240;
        }
        public void introduce() {
            System.out.println("bradn:" + brand + ";color" + color + "; maxSpeed:" + maxSpeed);
        }
        // DisposableBean接口方法
        public void destroy() throws Exception {
            System.out.println("调用DisposableBean.destroy()");
        }
        // 通过<bean>的destory-method属性指定的销毁方法
        public void myDestory() {
            System.out.println("调用destory-method所指定的myDestory()方法。");
        }
    }

    InstantiationAwareBeanPostProcessor实现类

    package com.yangjun.bean;
    
    import java.beans.PropertyDescriptor;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.PropertyValues;
    import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;
    
    @SuppressWarnings("unchecked")
    public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    
        // 接口方法:实例化bean前进行调用
        public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException {
            // 1-1仅对容器中的car-bean进行处理
            if ("car".equals(beanName)) {
                System.out.println("InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()");
            }
            return null;
        }
    
        // 接口方法:在实例化bean后进行调用
        public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
            if ("car".equals(beanName)) {
                System.out.println("InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()");
            }
            return true;
        }
    
        // 接口方法:在设置某个属性时调用
        public PropertyValues postProcessPropertyValues(PropertyValues propertyvalues,
                PropertyDescriptor apropertydescriptor[], Object bean, String beanName) throws BeansException {
            // 3-1仅对容器中car-bean进行处理,还可以通过post入参进行过滤,
            // 仅对car的某个特定属性进行处理
            if ("car".equals(beanName)) {
                System.out.println("InstantiationAwareBeanPostProcessor.postProcessPropertyValues");
            }
            return propertyvalues;
        }
    }

    BeanPostProcessor实现类

    package com.yangjun.bean;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class MyBeanPostProcessor implements BeanPostProcessor {
    
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            if (beanName.equals("car")) {
                Car car = (Car) bean;
                if (car.getColor() == null) {
                    System.out.println("调用BeanPostProcessor.postProcessBeforeInitialization(),color为空,设置为默认黑色.");
                    car.setColor("黑色");
                }
            }
            return bean;
        }
    
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    
            if (beanName.equals("car")) {
                Car car = (Car) bean;
                if (car.getMaxSpeed() >= 200) {
                    System.out.println("调用BeanPostProcessor.postProcessAfterInitialization(),将maxSpedd调整为200.");
                    car.setMaxSpeed(200);
                }
            }
            return bean;
        }
    
    }

    在Spring配置文件中定义Car的配置信息

    <?xml version="1.0" encoding="UTF-8"?>
    
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:p="http://www.springframework.org/schema/p" 
        xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
    
        <bean id="helloWorld" class="com.yangjun.bean.HelloWorld" scope="prototype">
            <property name="message" value="杨峻!" />
        </bean>
    
        <bean id="car" class="com.yangjun.bean.Car" init-method="myInit" destroy-method="myDestory" 
            p:brand="红旗CA72" 
            p:maxSpeed="300" 
            scope="singleton"
        />
    
    </beans>

    让容器装载配置文件,然后再分别注册上面所提供的两个后处理器:

    package com.yangjun.beanfactory;
    
    import org.springframework.beans.factory.BeanFactory;
    import org.springframework.beans.factory.config.ConfigurableBeanFactory;
    import org.springframework.beans.factory.xml.XmlBeanFactory;
    import org.springframework.core.io.ClassPathResource;
    import org.springframework.core.io.Resource;
    
    import com.yangjun.bean.Car;
    import com.yangjun.bean.MyBeanPostProcessor;
    import com.yangjun.bean.MyInstantiationAwareBeanPostProcessor;
    
    public class BeanLifeCycle {
    
        private static void LifiCycleInBeanFactory() {
            // 第1步:装载配置文件,并启动容器
            Resource res = new ClassPathResource("beans.xml");
            BeanFactory bf = new XmlBeanFactory(res);
    
            // 第2步:向容器中注册MyBeanPostProcesser处理器
            ((ConfigurableBeanFactory) bf).addBeanPostProcessor(new MyBeanPostProcessor());
            // 第3步:向容器中注册MyInstantiationAwareBeanPostProcessor后处理器
            ((ConfigurableBeanFactory) bf).addBeanPostProcessor(new MyInstantiationAwareBeanPostProcessor());
    
            // 第4步:第一次从容器中获取car,将处罚容器实例化该Bean,这将引发Bean生命周期方法的调用
            Car car1 = (Car) bf.getBean("car");
            car1.introduce();
            car1.setColor("红色");
    
            // 第5步:第二次从容器中获取car,直接从缓存池中取(因为 scope="singleton")
            Car car2 = (Car) bf.getBean("car");
    
            // 第6步:查看car1和car2是否指向同一引用
            System.out.println("car1==car2" + (car1 == car2));
    
            // 第7步:关闭容器
            ((XmlBeanFactory) bf).destroySingletons();
    
        }
    
        public static void main(String[] args) {
            LifiCycleInBeanFactory();
        }
    
    }

    流程说明:

    这里写图片描述

    展开全文
  • 搭建完spring boot的demo后自然要实现自动注入来体现spring ioc的便利了,但是我在实施过程中出现了这么... Description:Field helloService in com.example.demo.service.TestController required a bean of type 'co

    搭建完spring boot的demo后自然要实现自动注入来体现spring ioc的便利了,但是我在实施过程中出现了这么一个问题,见下面,这里找到解决办法记录下来,供遇到同样的问题的同僚参考

    Description:
    
    Field helloService in com.example.demo.service.TestController required a bean of type 'com.example.service.HelloService' that could not be found.
    
    
    Action:
    
    Consider defining a bean of type 'com.example.service.HelloService' in your configuration.
    

    然后我又看了下自己写的几个类以及注解见下面,感觉写的没有问题啊
      控制器 TestController
      这里写图片描述
      接口HelloService
      这里写图片描述
      接口对应的实现类HelloServiceImpl
      这里写图片描述
      
      根据英文的提示是在配置中找不到一个指定自动注入类型的bean,经过多方排查得出结论:
      正常情况下加上@Component注解的类会自动被Spring扫描到生成Bean注册到spring容器中,既然他说没找到,也就是该注解被没有被spring识别,问题的核心关键就在application类的注解SpringBootApplication上
      这里写图片描述
      这个注解其实相当于下面这一堆注解的效果,其中一个注解就是@Component,在默认情况下只能扫描与控制器在同一个包下以及其子包下的@Component注解,以及能将指定注解的类自动注册为Bean的@Service@Controller和@ Repository,至此明白问题所在,之前我将接口与对应实现类放在了与控制器所在包的同一级目录下,这样的注解自然是无法被识别的

    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan(excludeFilters={@Filter(type=CUSTOM, classes={TypeExcludeFilter.class}), @Filter(type=CUSTOM, classes={AutoConfigurationExcludeFilter.class})})
    @Target(value={TYPE})
    @Retention(value=RUNTIME)
    @Documented
    @Inherited
    

    至此,得出两种解决办法:
      1 .将接口与对应的实现类放在与application启动类的同一个目录或者他的子目录下,这样注解可以被扫描到,这是最省事的办法
      2 .在指定的application类上加上这么一行注解,手动指定application类要扫描哪些包下的注解,见下图
      这里写图片描述
      
      通过这两种方式,那个找不到指定Bean的错误就成功解决了。。。。。那么这篇就这样吧
      PS:控制器Controller也要放在与application同级或者子目录下,道理大致一样

    展开全文
  • bean

    千次阅读 2009-12-15 15:22:00
    bean:cookiecookie最早是由Netscape公司提出来的,用来存储客户的少量状态信息。如果您对cookie的具体细节感兴趣可以查阅参考资料中的cookie spec。 bean:cookie标签取回请求中名称为name的cookie的值。如果没有指定...

    bean:cookie

    cookie最早是由Netscape公司提出来的,用来存储客户的少量状态信息。如果您对cookie的具体细节感兴趣可以查阅参考资料中的cookie spec。

    bean:cookie标签取回请求中名称为name的cookie的值。如果没有指定multiple属性则依据刚取回的值创建一个Cookie类型的bean。如果指定了multiple属性则依据刚取回的值创建一个Cookie[]类型的数组。然后用id属性值将Cookie或Cookie[]绑定到page作用域中(这种绑定是为了其它标签能够使用该值),并创建对应的scripting变量(这种变量是为了JSP脚本能够使用该值)。

    下面的代码片段示例了如何使用bean:cookie标签读取名为JSESSIONID的cookie的值,并且使用了两种方式进行了输出:

    <logic:present cookie="JSESSIONID">
        <bean:cookie id="jSession" name="JSESSIONID"/>
        <!-- 其它标签通过绑定到page作用域中的属性使用该值 -->
        这个cookie的名称是<bean:write name="jSession" property="name"/>,
        值为<bean:write name="jSession" property="value"/>。<br/>
        <!-- JSP脚本通过scripting变量使用该值 -->
        <%
          String name = jSession.getName();
          String value = jSession.getValue();
          out.println("这个cookie的名称是"+name+",值为"+value+"。
          <br/>"); 
        %>
    </logic:present>
    

    bean:define

    bean:define标签在toScope(如果没有指定值就使用page作用域)指定的作用域中创建一个新属性,同时创建一个scripting变量。我们可以通过id值使用它们。新创建的属性可以由其它标签使用,而新创建的scripting变量可以由JSP脚本使用。

    我们可以使用三种方式为新创建的属性和scripting变量赋值:

    • 通过该标签的name、property和scope取回值,并且保持类型的一致性,除非取回的值为Java的原始类型,这时会使用适合的包装器类对这些值进行包装。
    • 通过该标签的value指定值,这时新创建的属性和scripting变量的类型为java.lang.String。
    • 通过在该标签的体中嵌入值,这时新创建的属性和scripting变量的类型为java.lang.String。

     

    下面的代码片段示例了如何使用bean:define标签创建新属性values和新scripting变量values,它将listForm中persons的值取出来赋给values:

    <bean:define id="values" name="listForm" property = "persons" 
     type="java.util.List"/> 
    

    下面给出ListForm的代码片段以帮助您更好的理解,其中Person是一个只有id和name两个属性的简单bean:

    public class ListForm extends ActionForm {
        private List<Person> persons = null;
        public List<Person> getPersons() {
          return persons;
        }
        public void setPersons(List<Person> persons) {
          this.persons = persons;
        }
        public void reset(ActionMapping mapping, 
            HttpServletRequest request) {
          persons = null;
        }
    } 
    

    下面的代码片段示例了logic:iterate标签如何使用bean:define标签创建的新属性values:

    <logic:iterate id="person" name="values">
        <bean:write name="person" property="id"/><br/>
    </logic:iterate>
    

    下面的代码片段示例了JSP脚本如何使用bean:define标签创建的新scripting变量values:

    <%
        Person p = new Person();
        for(int i=0;i<values.size();i++){
          p = (Person)values.get(i);
          out.println(p.getId());
          out.println("<br/>");
        }   
    %>
    

    bean:header

    bean:header标签取回请求中名称为name的header的值。如果没有指定multiple属性则依据刚取回的值创建一个String类型的bean。如果指定了multiple属性则依据刚取回的值创建一个String[]类型的数组。然后用id属性值将String或String[]绑定到page作用域中(这种绑定是为了其它标签能够使用该值),并创建对应的scripting变量(这种变量是为了JSP脚本能够使用该值)。

    下面是我的浏览器发送的header的内容,这些内容和浏览器有关,因此您的浏览器发送的内容可能和下面列出的不同。不过这没有关系,因为要理解bean:header标签您只要对这些内容有一个大概的认识就足够了。

    accept: */* 
    accept-language: zh-cn 
    accept-encoding: gzip, deflate 
    user-agent: Mozilla/4.0 (compatible; MSIE 6.0; //应该在同一行
        Windows NT 5.1; SV1; .NET CLR 1.1.4322) 
    host: localhost:8080 
    connection: Keep-Alive 
    

    下面的代码片段示例了如何使用bean:header标签读取名为User-Agent的header的值,并且使用了两种方式进行了输出:

    <logic:present header="User-Agent">
        <!-- 其它标签通过绑定到page作用域中的属性使用该值 -->
        您的浏览器是<bean:header id="userAgent" name="User-Agent"/>
        <bean:write name="userAgent"/>。<br/>
        <!-- JSP脚本通过scripting变量使用该值 -->
        <%
          out.println("您的浏览器是"+userAgent+"。<br/>"); 
        %>
    </logic:present>
    

    bean:include

    bean:include标签对指定url(由forward、href或page确定)处的资源做一个请求,将响应数据作为一个String类型的bean绑定到page作用域,同时创建一个scripting变量。我们可以通过id值访问它们。

    下面的代码片段示例了bean:include标签的用法,其中include.txt文件包含要include的内容,然后将这些内容输出:

    <bean:include id="value" page="/include.txt"/>
    <!-- 其它标签通过绑定到page作用域中的属性使用该值 -->
    <bean:write name="value"/><br/>
    <!-- JSP脚本通过scripting变量使用该值 -->
    <%
        out.println(value); 
    %>
    

    bean:message

    bean:message标签用来从指定的locale中取回国际化的消息并输出,在这个过程中我们还可以传递五个以内的参数。message key可以通过key直接指定,也可以通过name和property间接的指定。

    bean:message标签有两种指定message key的方式,一是通过key属性直接指定;二是通过name和property属性间接的指定,其中message key是在message resources文件中定义的。

    我们可以在struts-config.xml文件中使用<message-resources>来设置message resources文件。

    为了介绍该标签我使用了三个message resources文件,三个文件的名字分别为Resources.properties、Resources_en.properties和Resources_zh.properties。在struts-config.xml文件中的设置(这里不用设置三个,struts会依据locale自动找到对应的文件)如下:

    <message-resources parameter="Resources" />
    

    三个message resources文件中定义的message key为:

    <!-- Resources.properties -->
    resource=Resources.properties.
    from=Resources.properties.
    <!-- Resources_en.properties -->
    from=Resources_en.properties.
    <!-- Resources_zh.properties 
        因为文件的编码被限制为ISO8859所以要有汉字必须用jdk的native2ascii提前转换 
    -->
    from=Resources_zh.properties.
    

    下面的代码片段示例了bean:message标签的用法:

    <bean:message key="from"/><br/>
    <bean:message key="resource"/><br/>
    <html:link action="/locale?language=en">English</html:link>
    <html:link action="/locale?language=zh">Chinese</html:link>
    

    上面的代码中含有改变locale的两个html:link标签,要使它们工作您的struts-config.xml文件中必须含有下面定义的form和action:

    <form-bean name="localeForm" 
          type="org.apache.struts.action.DynaActionForm">
        <form-property name="language" type="java.lang.String" />
        <form-property name="country" type="java.lang.String" />
        <!--action成功后要跳到那里-->
        <form-property name="page"    type="java.lang.String" 
          initial="/message.jsp"/>
    </form-bean>
     
    <action path="/locale" type="org.apache.struts.actions.LocaleAction"
        name="localeForm" scope="request">
    </action>
    

    在不同的locale下我们得到了如下的两个结果:

    在locale为zh时的结果:
    Resources_zh.properties.
    Resources.properties.
    在locale为en时的结果: 
    Resources_en.properties.
    Resources.properties.
    

    让我们来看一下在locale为zh时如何得到的是上面的结果。因为locale为zh所以<bean:message key="from"/><br/>先找Resources_zh.properties这个文件从中得到form键的值。而<bean:message key="resource"/><br/>也会先找Resources_zh.properties这个文件但这次没有找到resource键,这时Struts会到Resources.properties这个文件中找,很幸运这里找到了。如果还没有找到,或message resource文件不存在就会抛出异常。当locale为en时类似,您可以自己试试。

    bean:page

    bean:page标签将页上下文中的application、config、request、response 或 session取出,然后用id属性值将它们绑定到page作用域中(这种绑定是为了其它标签能够使用该值),并创建对应的scripting变量(这种变量是为了JSP脚本能够使用该值)。

    下面的代码片段示例了bean:page标签取出response,然后使用bean:write标签将response的characterEncoding和contentType属性输出:

    <bean:page id="res" property="response"/>
    <!-- 其它标签通过绑定到page作用域中的属性使用该值 -->
    <bean:write name="res" property="characterEncoding"/><br/>
    <bean:write name="res" property="contentType"/><br/>
    <!-- JSP脚本通过scripting变量使用该值 -->
    <%
        String characterEncoding = res.getCharacterEncoding();
        String contentType = res.getContentType();
        out.println(characterEncoding+"<br/>"); 
        out.println(contentType+"<br/>"); 
    %>
    

    您可以用和上面类似的代码访问application、config、request 或 session中的任何一个对象。

    bean:parameter

    bean:parameter标签取回请求中的参数值。如果没有指定multiple属性则依据刚取回的值创建一个String类型的bean。如果指定了multiple属性则依据刚取回的值创建一个String[]类型的数组。然后用id属性值将String或String[]绑定到page作用域中(这种绑定是为了其它标签能够使用该值),并创建对应的scripting变量(这种变量是为了JSP脚本能够使用该值)。

    下面的两个代码片段使用相同的url传递参数,url的形式为http://127.0.0.1:8080/struts-demo/parameter.jsp?param=1&param=2&param=3。前面的代码片段中没有指定multiple属性,因此p是String类型而且仅仅读取了参数的第一个值。后面的代码片段中指定了multiple属性的值,因此ps是String[]类型的包含所有参数的值。

    <bean:parameter id="p" name="param"/>
    <bean:write name="p"/>
    
    <bean:parameter id="ps" multiple="true" name="param"/>
    <logic:iterate id="p" name="ps">
        <bean:write name="p"/><br/>
    </logic:iterate>
    

    bean:resource

    bean:resource标签取回指定的web应用程序的资源,以InputStream或String的形式保存到page作用域中并且创建scripting变量。采用什么形式取决于标签的input属性,如果指定input则以InputStream的形式保存,如果没有指定input则以String的形式保存。

    下面的两个代码片段示例了bean:resource标签,其中resource.txt是要使用的资源文件。前面的代码片段中没有指定input属性,因此以String的形式处理资源文件,bean:write标签输出资源文件的内容。后面的代码片段中指定了input属性的值,因此以InputStream的形式使用资源文件,两个bean:write标签分别输出InputStream对象的实例名(如java.io.ByteArrayInputStream@16dadf9)和类名(如class java.io.ByteArrayInputStream)。

    <bean:resource id="str" name="/resource.txt"/>
    <!-- 其它标签通过绑定到page作用域中的属性使用该值 -->
    <bean:write name="str"/><br/>
    <!-- JSP脚本通过scripting变量使用该值 -->
    <%
        out.println(str+"<br/>");
    %>
    
    <bean:resource id="is" input="true" name="/resource.txt"/>
    <!-- 其它标签通过绑定到page作用域中的属性使用该值 -->
    <bean:write name="is"/><br/>
    <bean:write name="is" property="class"/>
    <!-- JSP脚本通过scripting变量使用该值 -->
    <%
        out.println(is+"<br/>");
        out.println(is.getClass()+"<br/>");
    %>
    

    bean:size

    bean:size标签创建一个java.lang.Integer类型的bean,这个bean的值为该标签指定的Collection或Map中所含元素的个数。 这可以和logic:iterate标签配合使用,因为logic:iterate标签不能得到所叠代的集合的元素的个数,这有时候很不方便。

    下面的代码片段示例了bean:size标签取出persons中还有元素的个数,其中listForm和persons的定义参见bean:define标签部分:

    <logic:notEmpty name="listForm" property = "persons">   
        <bean:size id="size" name="listForm" property = "persons"/>
        <bean:write name="size"/>   
    </logic:notEmpty>    
    

    bean:struts

    bean:struts标签取回Struts的内部对象formBean、forward或mapping的值,然后用id绑定到page作用域中(这种绑定是为了其它标签能够使用该值),并创建对应的scripting变量(这种变量是为了JSP脚本能够使用该值)。

    下面的代码片段示例了bean:struts标签取出listForm对象,让我们先来看一下listForm的定义在读代码:

    <!-- listForm的定义<form-bean name="listForm" 
        type="org.solo.struts.form.ListForm" /> -->
    <bean:struts id="listFormBean" formBean="listForm"/>
    name:<bean:write name="listFormBean" property="name"/><br/>
    type:<bean:write name="listFormBean" property="type"/><br/>
    dynamic:<bean:write name="listFormBean" property="dynamic"/><br/>
    

    上面代码运行的结果为:

    name:listForm 
    type:org.solo.struts.form.ListForm
    dynamic:false 
    

    bean:write

    bean:write标签将指定的bean的属性值写到当前的JspWriter中,并且可以对输出进行格式化。

    下面的代码片段示例了bean:write标签输出User-Agent:

    <logic:present header="User-Agent">
        <bean:header id="header" name="User-Agent"/>
        <bean:write name="header"/>
    </logic:present>
    

    下面的代码片段示例了bean:write标签格式化输出当前日期,其中now是在DataForm中定义的一个java.util.Date类型的域(值为new Date()),format.date.standard是在资源文件中的一个键(format.date.standard=yyyy-MM-dd):

    <bean:define id="date" name="dataForm" property="now"/>
    <br/><bean:write name="date"/>
    <br/><bean:write name="date" format="MM/dd/yyyy"/>
    <br/><bean:write name="date" formatKey="format.date.standard"/>
    

    上面代码运行的结果为:

    Sun Jun 04 17:04:05 CST 2006
    06/04/2006
    2006-06-04
    展开全文
  • Spring中bean的作用域与生命周期

    万次阅读 多人点赞 2017-06-17 22:29:18
    在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。而bean的定义...

      在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象,除此之外,bean就与应用程序中的其他对象没有什么区别了。而bean的定义以及bean相互间的依赖关系将通过配置元数据来描述。

      Spring中的bean默认都是单例的,对于Web应用来说,Web容器对于每个用户请求都创建一个单独的Sevlet线程来处理请求,引入Spring框架之后,每个Action都是单例的,那么对于Spring托管的单例Service Bean,Spring的单例是基于BeanFactory也就是Spring容器的,单例Bean在此容器内只有一个,Java的单例是基于JVM,每个JVM内只有一个实例。

    1、bean的作用域

      创建一个bean定义,其实质是用该bean定义对应的类来创建真正实例的“配方”。把bean定义看成一个配方很有意义,它与class很类似,只根据一张“处方”就可以创建多个实例。不仅可以控制注入到对象中的各种依赖和配置值,还可以控制该对象的作用域。这样可以灵活选择所建对象的作用域,而不必在Java Class级定义作用域。Spring Framework支持五种作用域,分别阐述如下表。

    Center

      五种作用域中,request、session和global session三种作用域仅在基于web的应用中使用(不必关心你所采用的是什么web应用框架),只能用在基于web的Spring ApplicationContext环境。

      (1)当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。Singleton是单例类型,就是在创建起容器时就同时自动创建了一个bean的对象,不管你是否使用,他都存在了,每次获取到的对象都是同一个对象。注意,Singleton作用域是Spring中的缺省作用域。要在XML中将bean定义成singleton,可以这样配置:

    <bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">
    

      (2)当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。根据经验,对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域。在XML中将bean定义成prototype,可以这样配置:

    <bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>  
     <!--或者-->
    <bean id="account" class="com.foo.DefaultAccount" singleton="false"/> 
    

      (3)当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例;即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

    <bean id="loginAction" class=com.foo.LoginAction" scope="request"/>
    

      针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效,因此可以根据需要放心的更改所建实例的内部状态,而其他请求中根据loginAction bean定义创建的实例,将不会看到这些特定于某个请求的状态变化。当处理请求结束,request作用域的bean实例将被销毁。

      (4)当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

    <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
    

      针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效。与request作用域一样,可以根据需要放心的更改所创建实例的内部状态,而别的HTTP Session中根据userPreferences创建的实例,将不会看到这些特定于某个HTTP Session的状态变化。当HTTP Session最终被废弃的时候,在该HTTP Session作用域内的bean也会被废弃掉。

      (5)当一个bean的作用域为Global Session,表示在一个全局的HTTP Session中,一个bean定义对应一个实例。典型情况下,仅在使用portlet context的时候有效。该作用域仅在基于web的Spring ApplicationContext情形下有效。考虑下面bean定义:

    <bean id="user" class="com.foo.Preferences "scope="globalSession"/>
    

      global session作用域类似于标准的HTTP Session作用域,不过仅仅在基于portlet的web应用中才有意义。Portlet规范定义了全局Session的概念,它被所有构成某个portlet web应用的各种不同的portlet所共享。在global session作用域中定义的bean被限定于全局portlet Session的生命周期范围内。

    2、bean的生命周期

      Spring中Bean的实例化过程:

    Center

      Bean的生命周期:

    2020111815000245.png

      Bean实例生命周期的执行过程如下:

    • Spring对bean进行实例化,默认bean是单例;

    • Spring对bean进行依赖注入;

    • 如果bean实现了BeanNameAware接口,Spring将bean的名称传给setBeanName()方法;

    • 如果bean实现了BeanFactoryAware接口,Spring将调用setBeanFactory()方法,将BeanFactory实例传进来;

    • 如果bean实现了ApplicationContextAware接口,它的setApplicationContext()方法将被调用,将应用上下文的引用传入到bean中;

    • 如果bean实现了BeanPostProcessor接口,它的postProcessBeforeInitialization()方法将被调用;

    • 如果bean中有方法添加了@PostConstruct注解,那么该方法将被调用;

    • 如果bean实现了InitializingBean接口,spring将调用它的afterPropertiesSet()接口方法,类似的如果bean使用了init-method属性声明了初始化方法,该方法也会被调用;

    • 如果在xml文件中通过<bean>标签的init-method元素指定了初始化方法,那么该方法将被调用;

    • 如果bean实现了BeanPostProcessor接口,它的postProcessAfterInitialization()接口方法将被调用;

    • 此时bean已经准备就绪,可以被应用程序使用了,他们将一直驻留在应用上下文中,直到该应用上下文被销毁;

    • 如果bean中有方法添加了@PreDestroy注解,那么该方法将被调用;

    • 若bean实现了DisposableBean接口,spring将调用它的distroy()接口方法。同样的,如果bean使用了destroy-method属性声明了销毁方法,则该方法被调用;

      这里特别说明一下Aware接口,Spring的依赖注入最大亮点就是所有的Bean对Spring容器的存在是没有意识的。但是在实际项目中,我们有时不可避免的要用到Spring容器本身提供的资源,这时候要让 Bean主动意识到Spring容器的存在,才能调用Spring所提供的资源,这就是Spring的Aware接口,Aware接口是个标记接口,标记这一类接口是用来“感知”属性的,Aware的众多子接口则是表征了具体要“感知”什么属性。例如BeanNameAware接口用于“感知”自己的名称,ApplicationContextAware接口用于“感知”自己所处的上下文。其实Spring的Aware接口是Spring设计为框架内部使用的,在大多数情况下,我们不需要使用任何Aware接口,除非我们真的需要它们,实现了这些接口会使应用层代码耦合到Spring框架代码中

      其实很多时候我们并不会真的去实现上面所描述的那些接口,那么下面我们就除去那些接口,针对bean的单例和非单例来描述下bean的生命周期:

    2.1 单例管理的对象

      当scope="singleton",即默认情况下,会在启动容器时(即实例化容器时)时实例化。但我们可以指定Bean节点的lazy-init="true"来延迟初始化bean,这时候,只有在第一次获取bean时才会初始化bean,即第一次请求该bean时才初始化。如下配置:

    <bean id="serviceImpl" class="cn.csdn.service.ServiceImpl" lazy-init="true"/>
    

      如果想对所有的默认单例bean都应用延迟初始化,可以在根节点beans设置default-lazy-init属性为true,如下所示:

    <beans default-lazy-init="true">
    

      默认情况下,Spring在读取xml文件的时候,就会创建对象。在创建对象的时候先调用构造器,然后调用init-method属性值中所指定的方法。对象在被销毁的时候,会调用destroy-method属性值中所指定的方法(例如调用Container.destroy()方法的时候)。写一个测试类,代码如下:

    public class LifeBean {
    	private String name;  
        
        public LifeBean(){  
            System.out.println("LifeBean()构造函数");  
        }  
        public String getName() {  
            return name;  
        }  
      
        public void setName(String name) {  
            System.out.println("setName()");  
            this.name = name;  
        }  
    
        public void init(){  
            System.out.println("this is init of lifeBean");  
        }  
          
        public void destory(){  
            System.out.println("this is destory of lifeBean " + this);  
        }  
    }
    

      life.xml配置如下:

    <bean id="life_singleton" class="com.bean.LifeBean" scope="singleton" 
    			init-method="init" destroy-method="destory" lazy-init="true"/>
    

      测试代码如下:

    public class LifeTest {
    	@Test 
    	public void test() {
    		AbstractApplicationContext container = 
    		new ClassPathXmlApplicationContext("life.xml");
    		LifeBean life1 = (LifeBean)container.getBean("life");
    		System.out.println(life1);
    		container.close();
    	}
    }
    

      运行结果如下:

    LifeBean()构造函数
    this is init of lifeBean
    com.bean.LifeBean@573f2bb1
    ……
    this is destory of lifeBean com.bean.LifeBean@573f2bb1
    

    2.2 非单例管理的对象

      当scope="prototype"时,容器也会延迟初始化bean,Spring读取xml文件的时候,并不会立刻创建对象,而是在第一次请求该bean时才初始化(如调用getBean方法时)。在第一次请求每一个prototype的bean时,Spring容器都会调用其构造器创建这个对象,然后调用init-method属性值中所指定的方法。对象销毁的时候,Spring容器不会帮我们调用任何方法,因为是非单例,这个类型的对象有很多个,Spring容器一旦把这个对象交给你之后,就不再管理这个对象了。

      为了测试prototype bean的生命周期life.xml配置如下:

    <bean id="life_prototype" class="com.bean.LifeBean" scope="prototype" init-method="init" destroy-method="destory"/>
    

      测试程序如下:

    public class LifeTest {
    	@Test 
    	public void test() {
    		AbstractApplicationContext container = new ClassPathXmlApplicationContext("life.xml");
    		LifeBean life1 = (LifeBean)container.getBean("life_singleton");
    		System.out.println(life1);
    		
    		LifeBean life3 = (LifeBean)container.getBean("life_prototype");
    		System.out.println(life3);
    		container.close();
    	}
    }
    

      运行结果如下:

     
    LifeBean()构造函数
    this is init of lifeBean
    com.bean.LifeBean@573f2bb1
    LifeBean()构造函数
    this is init of lifeBean
    com.bean.LifeBean@5ae9a829
    ……
    this is destory of lifeBean com.bean.LifeBean@573f2bb1
    

      可以发现,对于作用域为prototype的bean,其destroy方法并没有被调用。如果bean的scope设为prototype时,当容器关闭时,destroy方法不会被调用。对于prototype作用域的bean,有一点非常重要,那就是Spring不能对一个prototype bean的整个生命周期负责:容器在初始化、配置、装饰或者是装配完一个prototype实例后,将它交给客户端,随后就对该prototype实例不闻不问了。不管何种作用域,容器都会调用所有对象的初始化生命周期回调方法。但对prototype而言,任何配置好的析构生命周期回调方法都将不会被调用。清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源,都是客户端代码的职责(让Spring容器释放被prototype作用域bean占用资源的一种可行方式是,通过使用bean的后置处理器,该处理器持有要被清除的bean的引用)。谈及prototype作用域的bean时,在某些方面你可以将Spring容器的角色看作是Java new操作的替代者,任何迟于该时间点的生命周期事宜都得交由客户端来处理。

      Spring容器可以管理singleton作用域下bean的生命周期,在此作用域下,Spring能够精确地知道bean何时被创建,何时初始化完成,以及何时被销毁。而对于prototype作用域的bean,Spring只负责创建,当容器创建了bean的实例后,bean的实例就交给了客户端的代码管理,Spring容器将不再跟踪其生命周期,并且不会管理那些被配置成prototype作用域的bean的生命周期。

    2.3 引申

      在学习Spring IoC过程中发现,每次产生ApplicationContext工厂的方式是:

    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    

      这样产生ApplicationContext就有一个弊端,每次访问加载bean的时候都会产生这个工厂,所以这里需要解决这个问题。

      ApplicationContext是一个接口,它继承自BeanFactory接口,除了包含BeanFactory的所有功能之外,在国际化支持、资源访问(如URL和文件)、事件传播等方面进行了良好的支持。

      解决问题的方法很简单,在web容器启动的时候将ApplicationContext转移到ServletContext中,因为在web应用中所有的Servlet都共享一个ServletContext对象。那么我们就可以利用ServletContextListener去监听ServletContext事件,当web应用启动的是时候,我们就将ApplicationContext装载到ServletContext中。 Spring容器底层已经为我们想到了这一点,在spring-web-xxx-release.jar包中有一个已经实现了ServletContextListener接口的类ContextLoader,其源码如下:

    public class ContextLoaderListener extends ContextLoader implements ServletContextListener {
    	private ContextLoader contextLoader;
    
    	public ContextLoaderListener() {
    
    	}
    
    	public ContextLoaderListener(WebApplicationContext context) {
    		super(context);
    	}
    
    	public void contextInitialized(ServletContextEvent event) {
    		this.contextLoader = createContextLoader();
    		if (this.contextLoader == null) {
    			this.contextLoader = this;
    		}
    		this.contextLoader.initWebApplicationContext(event.getServletContext());
    	}
    
    	@Deprecated
    	protected ContextLoader createContextLoader() {
    		return null;
    	}
    
    	@Deprecated
    	public ContextLoader getContextLoader() {
    		return this.contextLoader;
    	}
    
    	public void contextDestroyed(ServletContextEvent event) {
    		if (this.contextLoader != null) {
    		this.contextLoader.closeWebApplicationContext(event.getServletContext());
    		}
    		ContextCleanupListener.cleanupAttributes(event.getServletContext());
    	}
    }
    

      这里就监听到了servletContext的创建过程, 那么 这个类又是如何将applicationContext装入到serveletContext容器中的呢?

      this.contextLoader.initWebApplicationContext(event.getServletContext())方法的具体实现中:

    public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
         if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
             throw new IllegalStateException(
                     "Cannot initialize context because there is already a root application context present - " +
                     "check whether you have multiple ContextLoader* definitions in your web.xml!");
         }
    
         Log logger = LogFactory.getLog(ContextLoader.class);
         servletContext.log("Initializing Spring root WebApplicationContext");
         if (logger.isInfoEnabled()) {
             logger.info("Root WebApplicationContext: initialization started");
         }
         long startTime = System.currentTimeMillis();
    
         try {
         	  // Store context in local instance variable, to guarantee that
              // it is available on ServletContext shutdown.
             if (this.context == null) {
                 this.context = createWebApplicationContext(servletContext);
             }
             if (this.context instanceof ConfigurableWebApplicationContext) {
                 ConfigurableWebApplicationContext cwac = (ConfigurableWebApplicationContext) this.context;
                 if (!cwac.isActive()) {
                     // The context has not yet been refreshed -> provide services such as
                     // setting the parent context, setting the application context id, etc
                     if (cwac.getParent() == null) {
                         // The context instance was injected without an explicit parent ->
                         // determine parent for root web application context, if any.
                         ApplicationContext parent = loadParentContext(servletContext);
                         cwac.setParent(parent);
                     }
                     configureAndRefreshWebApplicationContext(cwac, servletContext);
                 }
             }
             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
    
             ClassLoader ccl = Thread.currentThread().getContextClassLoader();
             if (ccl == ContextLoader.class.getClassLoader()) {
                 currentContext = this.context;
             }
             else if (ccl != null) {
                 currentContextPerThread.put(ccl, this.context);
             }
    
             if (logger.isDebugEnabled()) {
                 logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
                         WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
             }
             if (logger.isInfoEnabled()) {
                 long elapsedTime = System.currentTimeMillis() - startTime;
                 logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
             }
    
             return this.context;
         }
         catch (RuntimeException ex) {
             logger.error("Context initialization failed", ex);
             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
             throw ex;
         }
         catch (Error err) {
             logger.error("Context initialization failed", err);
             servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
             throw err;
         }
     }
    

      这里的重点是servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context),用key:WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE value: this.context的形式将applicationContext装载到servletContext中了。另外从上面的一些注释我们可以看出: WEB-INF/applicationContext.xml, 如果我们项目中的配置文件不是这么一个路径的话 那么我们使用ContextLoaderListener 就会出问题, 所以我们还需要在web.xml中配置我们的applicationContext.xml配置文件的路径。

    <listener>
    	<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    
    <context-param>
    	<param-name>contextConfigLocation</param-name>
    	<param-value>classpath:applicationContext.xml</param-value>
    </context-param>
    

      剩下的就是在项目中开始使用 servletContext中装载的applicationContext对象了: 那么这里又有一个问题,装载时的key是 WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,我们在代码中真的要使用这个吗? 其实Spring为我们提供了一个工具类WebApplicationContextUtils,接着我们先看下如何使用,然后再去看下这个工具类的源码:

    WebApplicationContext applicationContext = WebApplicationContextUtils.getWebApplicationContext(request.getServletContext());
    

      接着来看下这个工具类的源码:

    public static WebApplicationContext getWebApplicationContext(ServletContext sc) {
    	return getWebApplicationContext(sc, WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);
    }
    

      这里就能很直观清晰地看到 通过key值直接获取到装载到servletContext中的 applicationContext对象了。

      ContextLoaderListener监听器的作用就是启动Web容器时,自动装配ApplicationContext的配置信息,因为它实现了ServletContextListener这个接口,在web.xml配置这个监听器,启动容器时,就会默认执行它实现的方法。在ContextLoaderListener中关联了ContextLoader这个类,整个加载配置过程由ContextLoader来完成。

    展开全文
  • Spring 了解Bean的一生(生命周期)

    万次阅读 多人点赞 2018-04-25 22:29:00
    该篇博客就来了解IoC容器下Bean的一生吧,也可以理解为bean的生命周期。 首先你需要知道的知识 在IoC容器启动之后,并不会马上就实例化相应的bean,此时容器仅仅拥有所有对象的BeanDefinition(Bean...
  • org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionInterceptor' defined in ServletContext resource [/WEB-INF/applicationContext.xml]: Cannot resolve ...
  • Spring解析,加载及实例化Bean的顺序(零配置)

    万次阅读 多人点赞 2018-02-16 14:23:31
    Spring零配置下@Bean,@Import,@ComponentScan形式定义Bean的解析,加载及实例化顺序
  • Annotation-specified bean name 'DistrictServiceImpl' for bean class [com.qiu.service.impl.DoctorDetailServiceImpl] conflicts with existing, non-compatible bean definition of same...
  • Spring Bean详细讲解 什么是Bean?

    万次阅读 多人点赞 2018-11-19 15:45:37
    什么是Bean? Spring Bean是被实例的,组装的及被Spring 容器管理的Java对象。 Spring 容器会自动完成@bean对象的实例化。 创建应用对象之间的协作关系的行为称为:装配(wiring),这就是依赖注入的本质。 Spring ...
  • Bean注解的bean名字

    千次阅读 2018-11-19 01:05:42
    @Bean注解括号里面的字符串就是bean的名字,也可以不加,默认bean的名字是@Bean注解所对应的方法的方法名
  • 解决 No qualifying bean of type 问题

    万次阅读 2019-08-25 20:43:39
    解决 No qualifying bean of type 问题 思路: 1 检查是否添加了对应注解 2 检查配置是否正确,扫描包名, 类名及id是否正确 一. 传统SSM项目 ssm项目,出现“No qualifying bean of type found for dependency...
  • Spring中最重要的概念IOC和AOP,实际围绕的就是Bean的生成与使用。 什么叫做Bean呢?我们可以理解成对象,每一个你想交给Spring去托管的对象都可以称之为Bean。 今天通过Spring官方文档来了解下,如何生成bean...
  • 工厂beanbean工厂

    千次阅读 2018-04-12 13:16:08
    FactoryBean(工厂bean):是bean的加工工厂,是对已知bean的加工,是一个接口,要实现三个方法: 1.Object getObject()可以对bean进行加工添加功能。 2.Class getObjectType()。 3.Boolean isSingleton()。 Bf....
  • @bean

    千次阅读 2018-10-29 14:34:37
    Spring帮助我们管理Bean分为两个部分,一个...在自动配置的方式中,使用@Component去告诉Spring,我是一个bean,你要来管理我,然后使用@AutoWired注解去装配Bean(所谓装配,就是管理对象直接的协作关系)。然后在Jav...
  • 什么是Bean

    万次阅读 多人点赞 2018-07-21 21:29:15
    Bean在Spring和SpringMVC中无所不在,将这个概念内化很重要,下面分享一下我的想法:   一、Bean是啥 1、Java面向对象,对象有方法和属性,那么就需要对象实例来调用方法和属性(即实例化);   2、凡是有...
  • Spring中bean的生命周期

    万次阅读 2018-07-18 17:43:20
    Spring 中bean 的生命周期短暂吗? 在spring中,从BeanFactory或ApplicationContext取得的实例为Singleton,也就是预设为每一个Bean的别名只能维持一个实例,而不是每次都产生一个新的对象使用Singleton模式产生单一...
  • no qualifying bean of type bean的解决方法

    万次阅读 2019-07-02 18:55:35
    java程序编写时,当bean文件中有多个类而使用@Autowired时未进行指定就会出现这个错误,解决方法如下: 未解决前: manager处是报错的。 解决方法: 使用 @Qualifier和**@Service** 在实现的类处使用@Service标记:...
  • 使用spring注解注入bean

    万次阅读 2019-03-23 13:16:38
    bean id="person" class="com.spring.bean.Person" > <property name="age" value="18"></property> <property name="name" value="zhangsan"></property> &...
  • spring boot中我们常常会在configuration类中通过@Bean注解去声明Bean。 但是很多人不清楚默认情况下,通过@Bean注解声明的Bean的名称是什么? 请问,如下代码声明bean的名称是什么? @Configuration public class ...
  • 注意applicationContext.xml文件的路径配置,按自己项目spring配置文件的路径做相应的调整import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.support....
  • Spring中的bean的理解

    万次阅读 多人点赞 2019-03-11 17:02:29
    首先看一下spring中创建bean的方式 1. 使用构造器创建Bean实例 使用构造器来创建Bean实例是最常见的情况,如果不采用构造注入,Spring底层会调用Bean类的无参构造器来创建实例,因此要求该Bean提供无参的构造器。...
  • @Configuration 和 @Bean注解注入bean

    千次阅读 2019-05-29 10:34:26
    理解 @Configuration 和 @Bean 注释 在理想的场景中,您可以在表示应用程序上下文的 XML 中定义 bean。以下代码展示了创建课程用例中的上下文 XML 及 bean 定义: 清单 1. XML 与 bean 定义 <beans> <...
  • 使用注解装配 bean时发生错误。 @Resource private TaskService taskService; 2. 错误分析与解决 错误分析:犯了一个很低级的错误,TaskServiceImpl没有去实现TaskService接口,如下图所示...
  • 动态工厂 Bean和静态工厂Bean

    千次阅读 2017-07-26 23:54:33
    动态工厂 Bean 有些时候,项目中需要通过工厂类来创建 Bean 实例,而不能像前面例子中似的,直接由 Spring 容器来装配 Bean 实例。使用工厂模式创建 Bean 实例,就会使工厂类与要创建的Bean 类耦合到一起。(1 )将...
  • "<"/bean">" 如果用@Bean注解来加载 @Bean public Test getTest(){ Test test = new Test(); List<Test2> list = new ArrayList(); list.add(Test2); Test.setList(new Test2()); return test; } ...
  • spring动态获取bean

    万次阅读 2020-01-13 15:09:20
    在实际的项目中,在使用spring注解的方式管理bean时,只能通过注解或者配置文件注入的方式获取相应的bean。但是在某些特殊情况下,我们需要在一个普通的JAVA类中获取由spring所管理的bean,一下是解决方法,实现接口...
  • 在Spring的Bean配置中,存在这样两种情况: [xhtml] view plaincopy bean id="testManager" class="com.sw.TestManagerImpl" scope="singleton" />     bean id="testManager" class=...
  • 手动注册BeanDefinition获取bean实例

    千次阅读 2018-12-21 19:25:09
    简单实现一下如何手动注册BeanDefinition,从而让beanFactory返回给我们一个spring容器管理的单例bean(如果不显示设置,默认为单例)。首先让一个类注解为@Component的类实现接口BeanFactoryAware,实现如下方法,从而...
  • Spring bean 和单例bean的线程安全

    千次阅读 2018-10-12 18:17:17
    Bean的作用域  Spring 3中为Bean定义了5中作用域,分别为singleton(单例)、prototype(原型)、request、session和global session,5种作用域说明如下: singleton:单例模式,Spring IoC容器中只会存在一个...
  • Spring Bean 的生命周期

    万次阅读 多人点赞 2018-08-05 11:30:20
    一、BeanFactory实例化Bean相关接口 二、BeanFactory的bean生命周期相关代码 三、关于BeanFactory的Bean生命周期接口的总结 四、ApplicationContext的Bean生命周期 五、ApplicationContext的Bean生命周期代码...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 201,807
精华内容 80,722
关键字:

bean