Spring-IOC(2)

scope

<!--Spring使用scope标签来制定bean的作用域(默认为Singleton)-->
<bean id="singletonBean" class="com.fq.instance.SingletonBean" scope="singleton">
</bean>
<bean id="prototypeBean" class="com.fq.instance.PrototypeBean" scope="prototype">
</bean>

Bean生命周期

Spring初始化/销毁bean时, 有时需要作一些处理工作, 因此Spring可以在创建和销毁bean的时候调用bean的两个生命周期方法;

/**
 * Created by jifang on 15/12/6.
 */
public class LifecycleBean {
    public LifecycleBean() {
        System.out.println("Constructor ...");
    }
    /**
     * 声明周期方法需: 无参, 无返回值, 非static
     */
    public void setUp() {
        System.out.println("SetUp ...");
    }
    /**
     * 同上
     */
    public void tearDown() {
        System.out.println("TearDown ...");
    }
}

配置:

<!-- init-method属性配置初始化方法,destroy-method属性配置销毁方法-->
<bean id="lifecycleBean" class="com.fq.bean.LifecycleBean" init-method="setUp" destroy-method="tearDown">
</bean>
测试
/**
 * Created by jifang on 15/12/6.
 */
public class LifecycleBeanTest extends TestCase {
    private ClassPathXmlApplicationContext context;
    @Before
    public void setUp() throws Exception {
        context = new ClassPathXmlApplicationContext("spring/applicationContext.xml");
    }
    @Test
    public void testLifecycle(){
        LifecycleBean bean = context.getBean("lifecycleBean", LifecycleBean.class);
        System.out.println(bean);
    }
    @After
    public void tearDown() throws Exception {
        // 必须手动调用context的close方法, 才会执行bean的销毁方法
        context.close();
    }
}

初始化方法与构造方法的区别?

1) 构造方法为对象申请空间, 完成对象基本属性的初始化;

2) 初始化方法主要完成对象复杂构造过程;

3) Java建议将对象复杂构造过程单独抽取出初始化方法, 如javax.servlet.GenericServlet

的init方法

public void init(ServletConfig config) throws ServletException {
    this.config = config;
    this.init();
}

后处理器

Spring提供了BeanPostProcessor接口,在构造Bean对象执行对象初始化(init-method)方法时可以对Bean进行处理;

/**
 * Created by jifang on 15/12/6.
 */
public class PrintBeanProcessor implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        // 可以根据beanName来决定对那个Bean进行后处理操作
        if (beanName.equals("lifecycleBean")) {
            System.out.println("后处理bean -- process before ...");
        }
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 如果不制定beanName, 则默认处理所有Bean
        System.out.println("后处理bean -- process after ...");
        return bean;
    }
}

配置

<!-- 为Spring容器所用的bean, 不需配置id -->
<bean class="com.fq.processor.PrintBeanProcessor"></bean>

这样在执行init-method[setUp]的前后, 会分别执行BeanPostProcessor中的两个方法.

后处理器可以在对象构造过程中提供代理,这是AOP自动代理的核心.

XML依赖注入

Spring配置文件支持构造参数属性注入和Setter方法属性注入;

1. 构造参数注入

<bean id="bean" class="com.fq.di.Bean">
    <!--
        index   代表参数顺序(从0开始)
        name    代表参数名
        type    参数类型
        value   注入的参数值
        ref     引用另一个bean元素的id
     -->
    <constructor-arg index="0" type="java.lang.String" value="fei_qing"></constructor-arg>
    <constructor-arg index="1" type="java.lang.Double" value="3.14"></constructor-arg>
</bean>

2. Setter方法注入

<bean id="bean" class="com.fq.di.Bean">
    <!--
        name    属性名(congSetter方法获得)
        value   注入的参数值
        ref     引用的另一个bean的id
     -->
    <property name="name" value="fei_qing"></property>
    <property name="price" value="88.8"></property>
</bean>

3. p名称空间注入

P名称空间在spring2.5版本后引入, 目的是为了简化属性依赖注入(setter方法)

<!--
    p:属性名="XXX", 引入常量值
    p:属性名-ref="XXX", 引用其他Bean对象
-->
<bean id="bean" class="com.fq.di.Bean" p:name="feiqing" p:price="1188">
</bean>

4. SpEL表达式

在spring3.0之后,引入SpEL表达式,以简化属性注入.

#{表达式}, 通过value属性注入: 可以引用一个Bean对象/对象属性/对象方法… 详细可参考Spring 表达式语言(SpEL)

Bean

public class Car {
    private String logo;
    private double price;
    private String owner;
    public String getLogo() {
        return logo;
    }
    public void setLogo(String logo) {
        this.logo = logo;
    }
    public double getPrice() {
        return price;
    }
    public void setPrice(double price) {
        this.price = price;
    }
    public String getOwner() {
        return owner;
    }
    public void setOwner(String owner) {
        this.owner = owner;
    }
}
public class Employ {
    private String name;
    private Car car;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Car getCar() {
        return car;
    }
    public void setCar(Car car) {
        this.car = car;
    }
}

配置

<!--SpEL 使用#{}来引用/获取对象-->
<bean id="car" class="com.fq.di.Car">
    <property name="logo" value="#{'logo.pic'}"/>
    <property name="price" value="#{18.8}"/>
    <property name="owner" value="#{'feiqing'}"/>
</bean>
<bean id="employ" class="com.fq.di.Employ">
    <!-- 可以直接使用value来引用到对象, 而不是ref -->
    <property name="car" value="#{car}"/>
    <!-- 可以直接引用一个对象的属性 -->
    <!--<property name="name" value="#{car.owner}"/>-->
    <!-- 还可以直接调用对象的方法 -->
    <property name="name" value="#{car.getOwner().toUpperCase()}"/>
</bean>

4. 集合属性注入

java常见集合: List/Set/Map/Properties等, Spring为每种集合都提供一个标签进行注入;

Bean

public class CollectionBean {
    private List<String> list;
    private Set<String> set;
    private Map<String, String> map;
    private Properties properties;
    public List<String> getList() {
        return list;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    public Set<String> getSet() {
        return set;
    }
    public void setSet(Set<String> set) {
        this.set = set;
    }
    public Map<String, String> getMap() {
        return map;
    }
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    public Properties getProperties() {
        return properties;
    }
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
}

配置

<bean id="collectionBean" class="com.fq.di.CollectionBean">
    <property name="list">
        <list>
            <value>aa</value>
            <value>bb</value>
            <value>cc</value>
            <value>dd</value>
        </list>
    </property>
    <property name="set">
        <set>
            <value>11</value>
            <value>12</value>
            <value>11</value>
        </set>
    </property>
    <property name="map">
        <map>
            <entry key="key1" value="value1"/>
            <entry key="key2" value="value2"/>
        </map>
    </property>
    <property name="properties">
        <props>
            <prop key="key1">value_1</prop>
            <prop key="key2">value_2</prop>
        </props>
    </property>
</bean>

注解装配

注解配置Bean

在需要Spring管理的类上添加@Component注解

(@Component还可以指定组件名@Component(value = "xxx"))

@Component
public class Bean {
    private String name;
    private Double price;
    public Bean() {
    }
    public Bean(String name, Double price) {
        this.name = name;
        this.price = price;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Double getPrice() {
        return price;
    }
    public void setPrice(Double price) {
        this.price = price;
    }
}

引入context命名空间并批量扫描

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="com.fq.di"/>
</beans>

Spring细化@Component以细分组件功能,提供了以下三个等价注解:

注解

说明

@Controller

控制器,web层组件

@Service

业务类,业务层组件

@Repository

持久层组件

Bean作用域

通过@Scope注解指定作用域

@Component
@Scope("prototype")
public class Bean {
    // ...
}

Bean生命周期

销毁

Bean
public class Bean {
    @PostConstruct
    public void setUp(){
        System.out.println("setUp ...");
    }
    @PreDestroy
    public void tearDown(){
        System.out.println("tearDown ...");
    }
}

注解依赖注入

1. @Value

简单类型

@Component
public class Bean {
    @Value("feiqing")
    private String name;
    @Value("88.88")
    private Double price;
    // ....
}

复杂属性(使用SpEL表达式)

@Component
public class Bean {
    @Value("#{car}")
    private Car car;
    // ...
}

2. @Autowired

@Autowired 默认按照类型进行注入(如果容器中存在两个相同类型对象,则@Autowired无法注入)
@Component
public class Bean {
    @Autowired
    private Car car;
    // ....
}
@Autowired+@Qualifier指定注入Bean的id
@Component
public class Bean {
    @Autowired
    @Qualifier("car")
    private Car car;
    // ...
}

3. @Resource

Spring支持JSR-250规范,可以使用@Resource()进行属性注入,功能和@Autowired相同:

@Controller(value = "bean")
public class Bean {
    @Resource(name = "car")
    private Car car;
    //...
}

注解/XML混合

Bean定义使用XML,Bean关系依赖注入使用注解:

需要在applicationContext.xml中配置:

<context:annotation-config/>

该配置可以使@Resource、@PostConstruct、@PreDestroy、@Autowired注解生效.

如果在配置文件中使用了<context:component-scan base-package="xxx.xx"/>则具有了<context:annotation-config/>的效果, 不必再单独配置.

原文发布于微信公众号 - Java帮帮(javahelp)

原文发表时间:2017-01-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏冷冷

SpringMVC 提交表单400 Bad Request

第一种: 后台:  @RequestMapping(value="/add",method=RequestMethod.POST)     public Str...

2945
来自专栏Zephery

Spring中Bean

一、什么是Bean 1、Java面向对象,对象有方法和属性,那么就需要对象实例来调用方法和属性(即实例化); 2、凡是有方法或属性的类都需要实例化,这样才能具象...

2976
来自专栏函数式编程语言及工具

FunDA(3)- 流动数据行操作:FDAPipeLine operations using scalaz-stream-fs2

在上节讨论里我们介绍了数据行流式操作的设想,主要目的是把后台数据库的数据载入前端内存再拆分为强类型的数据行,这样我们可以对每行数据进行使用和处理。形象点描述就是...

2178
来自专栏斑斓

在Scala项目中使用Spring Cloud

由于Scala本身属于JVM下的语言,因此它能够较好地与Java项目融合在一起。在Scala中调用Java库,基本上与在Java中调用Java库的方式是相同的(...

4675
来自专栏JavaEdge

SpringMVC之Controller查找(Spring4.0.3/Spring5.0.4源码进化对比)0 摘要1 SpringMVC请求流程2 SpringMVC初始化过程总结

4196
来自专栏小樱的经验随笔

Codeforces 833E Caramel Clouds

E. Caramel Clouds time limit per test:3 seconds memory limit per test:256 megaby...

3367
来自专栏郭少华

Spring boot之JSON(二)

2034
来自专栏菩提树下的杨过

velocity模板引擎学习(3)-异常处理

按上回继续,前面写过一篇Spring MVC下的异常处理、及Spring MVC下的ajax异常处理,今天看下换成velocity模板引擎后,如何处理异常页面:...

2188
来自专栏JavaEdge

遨游springmvc之HandlerExceptionResolver1.前言2.原理4.总结

4545
来自专栏大神带我来搬砖

Spring mvc中统一对ResponseBody进行封装

在一个前后端分离的项目中,需要对后端RestController里返回的ResponseBody进行统一的封装,让所有的API结果的都是json对象,带有是否成...

972

扫码关注云+社区

领取腾讯云代金券