Spring基础(1)-从getbean开始

bean

  • 大家都可以背下来,spring有三种注入方式。构造方法/setter/注解。我们将采用最简单的setter方法进行演示。
  • 大家也可以背下来,spring实例话bean有三种方式,构造器(含默认构造器),静态工厂,实例工厂。我们将采用默认构造器(即使用构造器但是不配置构造器参数,使用类的无参构造器的方式)。
  • 大家也可以背下来,spring有三种配置方式,基于xml,基于注解,基于java代码。我们将采用第一种方式。我们将采用第一种方式进行演示。
public class SpringTest {
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                new String[]{"Beans.xml"});

        DemoBean demoBean = (DemoBean) ctx.getBean("helloWorld");
        demoBean.getMessage();

    }
}


public class DemoBean {
    private String message;
    //spring并不要求所有对象的字段都有set方法。但是,所有需要注入的字段必须有set方法。
    public void setMessage(String message){
        this.message  = message;
    }
    public void getMessage(){
        System.out.println("Your Message : " + message);
    }
    /*
    在使用构造器实例话的情况下 一个类,想成为一个spring bean,至少需要满足下列两者之一(在声明构造方法参数的情况下):
    有无参的构造函数
    没有任何构造函数
    */
    public DemoBean() {
        System.out.println("in constructor");
    }
    //配置的INIT函数在无参构造函数执行之后执行。
    public void INIT(){
        System.out.println("in init");
    }
}

<bean id="helloWorld" class="gdl.DemoBean" init-method="INIT">
<property name="message" value="Hello World!"/>
</bean>

InitializingBean接口

如果我们将上述bean的代码改成如下

public class DemoBean implements InitializingBean {
    private String message;
    public void setMessage(String message){
        System.out.println("in setter");
        this.message  = message;
    }
    public void getMessage(){
        System.out.println("Your Message : " + message);
    }

    public DemoBean() {
        System.out.println("in constructor");
    }

    public void INIT(){
        System.out.println("in init");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("in after property set");
    }
}

运行结果将是
in constructor
in setter
in after property set
in init
Your Message : Hello World!
由此可见InitializingBean.afterPropertiesSet字如其名,在属性注入之后运行。

BeanPostProcessor

spring负责bean的初始化。在初始化的时候完成AOP的注入。我们自然有一个问题,如果我们在初始化的时候就要切面呢!!我们需要在初始化的时候对所有bean进行统一的逻辑。显然我们不会愚蠢到每个bean的类里存在相同的代码。
我们将相关代码修改如下

//所有实现了该接口的bean将被优先实例化。BeanPostProcessor的bean不经过BeanPostProcessor的bean的处理过程。(不然不就乱套了)
public class DemoBeanInitAOP implements BeanPostProcessor {

    public DemoBeanInitAOP() {
        System.out.println("BeanPostProcessor constructor");
    }
    //Object o是刚刚完成实例化的对象,还没有完成属性注入。String s是这个对象的bean ID。
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        System.out.println("BeanPostProcessor after Init:"+ s);
        return o;
    }

    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        System.out.println("BeanPostProcessor before Init:"+ s);
        return o;
    }
}

    <bean id="hellowordlInitAOP" class="gdl.DemoBeanInitAOP">
    </bean>

输出如下
BeanPostProcessor constructor
in constructor
in setter
BeanPostProcessor before Init:helloWorld
in after property set
in init
BeanPostProcessor after Init:helloWorld
Your Message : Hello World!

代理

通过上述步骤,我们getbean获得的对象,就是对象本身,可不是什么代理。但是如果我们加上AOP设置。

    <aop:config>
        <!--首先定义一个切入点-->
        <aop:pointcut id="loggerCutpoint"
                      expression=
                              "execution(* gdl.DemoBean.*(..)) "
        />
        <!--然后定义一个切面,一个切面包含唯一有一个切面支持的bean-->
        <aop:aspect id="logAspect" ref="hellowordlAOP">
            <aop:around pointcut-ref="loggerCutpoint" method="log"/>
        </aop:aspect>
    </aop:config>


public class DemoBeanAOP {
    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("我在被监视程序之前。。。");
        Object object = joinPoint.proceed();
        System.out.println("我在被监视程序之后。。。" );
        return object;
    }
}

这样,被命中的bean就会被代理对象所替代。
如果输出其class,就会变成

gdl.DemoBean$$EnhancerBySpringCGLIB$$bfcae182

总结

当然,spring getbean远远没有这么简单。还有诸如循环依赖等等复杂的烧脑问题。这个我们将在后续文章中介绍。
这里,简单介绍下spring的getbean过程:
+ 首先完成所有BeanPostProcessor,listner bean的初始化,该步骤在context new的时候完成。二者按着上述顺序完成,注意,后者在初始化时也会经过第一个)
+ 对于其他的bean,如果lazy-init设置为true,则会在getbean时加载。否则,会在context new时完成初始化。
postProcessBeforeInitialization(所有) ->
bean的构造器 ->
属性注入 ->
InitializingBean.afterPropertiesSet(单个)->
init-method(单个) ->
postProcessAfterInitialization(所有)
如果没有设置lazy-init,那么,第一次getbean(或者context start)的时候会初始化所有bean。否则为使用时才创建bean。

猜你喜欢

转载自blog.csdn.net/define_us/article/details/80887067