[框架]spring-IOC

本文深入探讨了Spring框架的IOC(控制反转)和依赖注入概念,阐述了Bean的理解及其在Spring中的角色。内容包括BeanFactory和ApplicationContext的实现、XML配置bean的方式、Bean生命周期管理以及基于注解的实现。同时,还详细介绍了Bean的作用域,强调了如何根据对象的状态和线程安全性选择合适的作用域。
摘要由CSDN通过智能技术生成

spring

全家桶依赖管理

全家桶依赖通过artifactId区分,有tx、beans、aspect等支持,本文以5.2.12为验证版本,下为核心依赖:

<dependency>
 <groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${springframe.version}</version>
</dependency>

依赖注入&控制反转

思想很简单,本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的,这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转(Bean托管给Spring容器)。
形式上:将依赖对象的实例化交给其调用者,通过某种方式传入进来。
思想上:仔细理解的话可以发现这种托管比工厂还要方便,根据诉求直接拿出来,用户不关心甚至不感知工厂的存在。

Bean的理解

理论上,符合JavaBean规范的类和不符合JavaBean规范的POJO都可以配置成Bean,也就是说,基本上所有的类都可以配置成Bean并交由Spring控管。容器使用反射机制来创建对象和注入依赖,过度地使用对系统的性能会产生不必要的浪费。对于细粒度的域对象,类似于实体类就没有必要交由容器管理。从类实现的功能上看,交由容器控管的对象主要包括以下几种:
服务层对象:包括桌面应用中的逻辑功能类,以及Web MVC应用中的控制类、服务类。
数据访问对象:和数据库进行操作,对数据进行增、删、改、查的类对象及事务处理的相关类对象。
框架基础对象:例如框架用于注解支持的类和持久化框架整合的基础对象等。
Spring容器主要是对对象的生命周期和对依赖关系进行管理。从类的特征上看,具备单例特性的类都适合交由容器管理、依赖

基本使用

BeanFactory实现

ApplicationContext和XmlBeanFactory两种实现方式,通过classpath读取xml需在idea中将文件夹标记为Resource,前者更易用且继承了更多接口,具备了事件发布等额外功能,后者对于自定义BeanPostProfessor时需要显示绑定。

package spring.beanfactory;

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.ClassPathResource;
import spring.bean.Person;

/**
 * BeanFactory为基础接口
 * 常用的实现类XmlBeanFactory,5.2.12已结被标记废弃了
 * ApplicationContext从BeanFactory为继承两轮得到,基础实现类为ClassPathXmlApplicationContext
 */
public class BeanFactoryTest {
    public static void main(String[] args){
        //XmlBeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
        //Person p = (Person) beanFactory.getBean("person");
        //System.out.println(JSONObject.toJSONString(p));
        //入参支持数组、同时加载多个xml
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Person t = (Person) context.getBean("person2");
        System.out.println(JSONObject.toJSONString(t));
        Action action = (Action) context.getBean("action");
        System.out.println(JSONObject.toJSONString(action));
    }
}

xml注册bean方式

xml文件,注意头文件编写,默认bean都是单例的,除非明确需要prototype类型。
默认bean注册是不开启autowire的,即=no。如下为示例:

<?xml version="1.0" encoding="UTF-8"?>
<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.xsd">

    <!-- 通过getter、setter方法注入 -->
    <bean id="pat" class="spring.bean.Animals" scope="singleton">
        <property name="type" value="cat"></property>
    </bean>

    <!-- 通过ref方法注入 -->
    <bean id="person" class="spring.bean.Person" init-method="myInit"
        destroy-method="myDestroy" scope="singleton">
        <property name="name" value="bob">
            <!-- 对于集合类型的扩展在此支持 -->
        </property>
        <property name="address" value="Cq"></property>
        <property name="pat" ref="pat"></property>
    </bean>

    <!-- 通过cons注入 -->
    <bean id="action" class="spring.bean.Action">
        <constructor-arg name="type" value="test" index="0" type="String"></constructor-arg>
    </bean>

    <!--自动装配 byType的话不支持多个Bean-->
    <!--bean id="pat2" class="spring.bean.Animals" scope="singleton">
        <property name="type" value="cat"></property>
    </bean-->
    <bean id="person2" class="spring.bean.Person" autowire="byName">
        <property name="name" value="bob"></property>
        <property name="address" value="Cq2"></property>
    </bean>
</beans>

Bean生命周期

Spring提供了一些标志接口,来改变BeanFactory中bean的生命行为,如:InitializingBeanDisposableBean,对应构造、析构逻辑
实现了BeanFactoryAware接口的类,解释为被BeanFactory创建后,拥有一个指向创建它的BeanFactory的引用。通俗讲即BeanFactory通过这个接口来调用Bean,完成如名字等信息的通知。
示例Bean类:

package spring.bean;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;

/**
 * 通过实现接口干预Bean生命周期,观察效果
 * 其实老版本spring提供的init-method和destroy-method方式可以和代码解耦
 */
public class Person implements InitializingBean, DisposableBean, BeanFactoryAware, BeanNameAware {
    private String address;
    private String name;
    private Animals pat;
    private BeanFactory factory;
    private String beanName;

    public Animals getPat() {
        return pat;
    }

    public void setPat(Animals pat) {
        this.pat = pat;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    // 通过<bean>的init-method属性指定的初始化方法
    public void myInit() {
        System.out.println("【init-method】调用<beanXML>的init-method属性指定的初始化方法");
    }

    // 通过<bean>的destroy-method属性指定的初始化方法
    public void myDestroy() {
        System.out.println("【destroy-method】调用<beanXML>的destroy-method属性指定的初始化方法");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("Person is Initializing Bean");
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("Person is Destroying Bean");
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        System.out.println("BeanFactoryAware works here");
        this.factory = beanFactory;
    }

    @Override
    public void setBeanName(String name) {
        this.beanName = name;
    }
}

Spring内部通过BeanPostprofessor来处理能找到的标志接口和调用适当的方法,通俗讲,BeanFactory创建每一个bean,在初始化前后会得到各一个回调函数,BeanFactoryPostProfessor类似,但是通过factory管理时绑定方式不同,关注度低。

package spring.beanlife;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * BeanFactory创建每一个bean,在初始化前后会得到各一个回调函数
 */
public class MyBeanPostProfessor implements BeanPostProcessor {
    public MyBeanPostProfessor()
    {
        System.out.println("【BeanPostProcessor实现类构造器!!】");
    }
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName)
    {
        System.out.println("BeanPostProcessor接口方法BeforeInitialization对属性进行更改!");
        return bean;
    }
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName)
    {
        System.out.println("BeanPostProcessor接口方法AfterInitialization对属性进行更改!");
        return bean;
    }
}

BeanPostProfessor的自定义触发、扩展,与上方实现类等价,一个体系。

package spring.beanlife;

import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessorAdapter;

import java.beans.PropertyDescriptor;

/**
 * 也是BeanPostProfessor的实现体系,只是扩展了postProcessPropertyValues方法
 */
public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter {
    // 实例化Bean之前调用
    @Override
    public Object postProcessBeforeInstantiation(@SuppressWarnings("rawtypes") Class beanClass,
                                                 String beanName) {
        System.out.println("InstantiationAwareBeanPostProcessor"
                + "调用BeforeInstantiation方法");
        return null;
    }
    // 实例化Bean之后调用
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) {
        System.out.println("InstantiationAwareBeanPostProcessor"
                + "调用AfterInitialization方法");
        return bean;
    }
    // 设置某个属性时调用
    @Override
    public PropertyValues postProcessPropertyValues(PropertyValues pvs,
                                                    PropertyDescriptor[] pds, Object bean, String beanName) {
        System.out.println("InstantiationAwareBeanPostProcessor"
                + "调用PropertyValues方法,bean设置属性时触发");
        return pvs;
    }
}

结果示意:

package spring.beanlife;

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.core.io.ClassPathResource;
import spring.bean.Person;

/**
 *生命周期管理
 */
public class BeanLifeTest {
    public static void main(String[] args) {
        XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("beans.xml"));
        //MyBeanPostProfessor
        MyInstantiationAwareBeanPostProcessor bp = new MyInstantiationAwareBeanPostProcessor();
        factory.addBeanPostProcessor(bp);
        Person p = (Person) factory.getBean("person");
        System.out.println(JSONObject.toJSONString(p));
    }
}

可以看到加载顺序:BeanPostProfessor->BeanFactoryAware->afterPropertiesSet->init标签->BeanPostProcessor调用AfterInitialization方法

基于注解实现

spring-2.0及2.5引入了注解模式
@Bean是一个方法级别上的注解,主要用在@Configuration注解的类里,也可以用在@Component注解的类里,添加的bean的id为方法名
扫描bean通过xml配置,context:component-scan有一个use-default-filters属性默认为true,会扫描指定包下的全部的标识类。扩充标签支持了排除bean和扫描bean的方式,context:include-filter、context:include-filter ,filter过滤器有五种type:

assignable-指定扫描某个接口派生出来的类
annotation-指定扫描使用某个注解的类
aspectj-指定扫描AspectJ表达式相匹配的类
custom-指定扫描自定义的实现了org.springframework.core.type.filter.TypeFilter接口的类
regex-指定扫描符合正则表达式的类

示例如下:

<?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="spring.*" use-default-filters="false">
	<!-- 扫描包路径下所有注解类标识的bean,并非只有Component -->
	<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
	</context:component-scan>
 </beans> 

注解示例代码:

package spring.annotation;

import com.alibaba.fastjson.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import spring.bean.Action;
import spring.bean.User;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;

@Service(value = "UserService")
public class UserService {

    @Resource
    User user;

    @Autowired
    @Qualifier("user2")
    Action action;
    
    @PostConstruct
    private void init()
    {
        System.out.println("Init with postConstruct");
    }
    @PreDestroy
    private void destroy()
    {
        System.out.println("destroy with preDestroy");
    }
    public void getUser()
    {
        System.out.println(JSONObject.toJSONString(user));
        System.out.println(JSONObject.toJSONString(action));
    }
    public User getBeanUser()
    {
        return user;
    }
}

涉及实体类:

package spring.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class User {
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    //Value用法
    @Value("${is_center:true}:bob")
    private String name;
    
    @Bean
    public Animals getAnimals()
    {
        return new Animals();
    }
}
package spring.bean;

import org.springframework.stereotype.Component;

@Component(value = "user2")
public class Action {

    private String type;

    public Action()
    {

    }

    public Action(String type)
    {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }

}

/**
 * 通过子类干扰Bean加载
 */
@Component
class ActionSon extends Action
{

}

主程序:

package spring.annotation;

import com.alibaba.fastjson.JSONObject;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import spring.bean.Animals;

/**
 * bean名默认类名首字母小写
 */
public class AnnotationTest {

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
        UserService sev = (UserService) context.getBean("UserService");
        sev.getUser();
        System.out.println(JSONObject.toJSONString(sev.getBeanUser().getAnimals()));
    }
}

bean作用域

spring-bean作用域
对于有状态的自然应该定义为prototype,非线程安全的自然可以通过threadlocal或者枷锁保证,全局变量也可以改为局部变量。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值