ssm笔记一(IoC一)

5 篇文章 0 订阅

Spring IoC容器和Beans介绍

全称

IoC:Inverse of Control 控制反转
DI:Dependecy Injection 依赖注入
以上两者是相同的。均表示将控制权交给Spring容器。

IoC的基础包

org.springframework.beans
org.springframework.context

<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-beans</artifactId>
	<version>5.2.4.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.springframework</groupId>
	<artifactId>spring-context</artifactId>
	<version>5.2.4.RELEASE</version>
</dependency>
BeanFactory

BeanFactory 接口提供了一种高级配置机制,能够管理任何类型的对象。

ApplicationContext 是BeanFactory的一个 子接口

ApplicationContext增加了以下几个功能:
在这里插入图片描述1、更容易与Spring的AOP特性集成。
2、消息资源处理(用于国际化)。
3、事件发布。
4、特定应用层上下文,例如用于web应用程序的 WebApplicationContext

在Spring中,构成应用程序主干并由Spring IoC容器管理的对象称为 beans

beans以及它们之间的依赖关系反映在容器使用的配置元数据中。

容器概述

org.springframework.context.ApplicationCotenxt 接口代表Spring IoC容器,它负责实例、配置和装配beans。

配置的元数据放到 XMLJava注解 或者 Java代码

创建容器实例

在独立应用程序中,通常创建 ClassPathXmlApplicationContextFileSystemXmlApplicationContext 的实例。

ApplicationContext applicationContext = new ClassPathXmlApplicationContext(path);
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(path);

path为配置文件路径,其中ClassPathXmlApplicationContext的路径为类路径的 相对路径,FileSystemXmlApplication的路径为 绝对路径

配置元数据

基于XML配置文件的beans要放在<beans>标签的<bean>标签中。
基于注解配置的beans需要放在含有 @Configuration 类中,并用 @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"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="..." class="...">  
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <bean id="..." class="...">
        <!-- collaborators and configuration for this bean go here -->
    </bean>

    <!-- more bean definitions go here -->
</beans>

其中id为标识,class为类。可用import标签导入其他xml文件,其中import标签的resource属性表示文件路径。

使用容器

使用ApplicationContext的 getBean 方法。

Bean配置

class属性

封装成的类,通常是必须的,可以通过两种方式用class属性。
1、Spring容器通过反射直接调用类的构造方法。
2、使用静态工厂方法。

构造内部类:使用 外部类$内部类

通过构造器实例化

<bean id="exampleBean" class="examples.ExampleBean"/>
<bean name="anotherExample" class="examples.ExampleBeanTwo"/>

通过静态工厂方法实例化
使用属性 factory-method

<bean id="clientService" 
	class="examples.ClientService"
	fatory-metho="createInstance"/>
public class ClientService {
	private static ClientService clientService = new ClientService();
	private ClientService() {}

	public static ClientService createInstance() {
		return clientService;
	}
}

使用实例工厂实例化
使用属性 factory-beanfactory-method

<bean id="serviceLocator" class="examples.DefaultServiceLocator"/>
<bean id="clientService"
	factory-bean="serviceLocaor"
	factory-method="createClientServiceInstance"/>
public class DefaultServiceLocator {
	private static ClientService clientService = new ClientServiceImpl();

	public clientService createClientServiceInstance() {
		return clientService;
	}
}
name属性

bean的名称,当有多个名称时可以用 ,;空格 隔开,除了第一个名称,其他被当作为别名。

id属性为 xsd:id 类型,不能包含特殊的字符,唯一性是容器强制约束的。
name属性为 xsd:string 类型,可以包含特殊的字符。

bean可以通过 ref属性 与其他bean关联(值为该bean的标识)。

别名:

<alias name="myApp-dataSource" alias="subsystemA-dataSource"/>
<alias name="myApp-dataSource" alias="subsystemB-dataSource"/>
scope属性

设定bean实例的作用域:
singleton(单例,默认)prototype(原型)、request、session、application、websocket。

当单例的bean要使用非单例的bean时,会出现问题,可以通过实现 ApplicationContextAware 接口解决。这种方法与Spring框架绑定,并不可取。

lookup方法注入
基于CGLIB类包,CGLIB可以在运行期操作Class字节码,为Bean动态创建子类或实现类。

package fiona.apple;

// no more Spring imports!

public abstract class CommandManager {

    public Object process(Object commandState) {
        // grab a new instance of the appropriate Command interface
        Command command = createCommand();
        // set the state on the (hopefully brand new) Command instance
        command.setState(commandState);
        return command.execute();
    }

    // okay... but where is the implementation of this method?
    protected abstract Command createCommand();
}

要注入的方法名称格式:

<public|protected> [abstract] <return-type> theMethodName(no-arguments);
<!-- a stateful bean deployed as a prototype (non-singleton) -->
<bean id="myCommand" class="fiona.apple.AsyncCommand" scope="prototype">
    <!-- inject dependencies here as required -->
</bean>

<!-- commandProcessor uses statefulCommandHelper -->
<bean id="commandManager" class="fiona.apple.CommandManager">
    <lookup-method name="createCommand" bean="myCommand"/>
</bean>

或者使用 @Lookup 注解。

public abstract class CommandManager {

    public Object process(Object commandState) {
        Command command = createCommand();
        command.setState(commandState);
        return command.execute();
    }

    @Lookup("myCommand")
    protected abstract Command createCommand();
}

任意方法替换(Arbitrary Method Replacement):
不如Lookup。实现 MethodReplacer 接口。

public class MyValueCalculator {

    public String computeValue(String input) {
        // some real code...
    }

    // some other methods...
}
/**
 * meant to be used to override the existing computeValue(String)
 * implementation in MyValueCalculator
 */
public class ReplacementComputeValue implements MethodReplacer {

    public Object reimplement(Object o, Method m, Object[] args) throws Throwable {
        // get the input value, work with it, and return a computed result
        String input = (String) args[0];
        ...
        return ...;
    }
}
<bean id="myValueCalculator" class="x.y.z.MyValueCalculator">
    <!-- arbitrary method replacement -->
    <replaced-method name="computeValue" replacer="replacementComputeValue">
        <arg-type>String</arg-type>
    </replaced-method>
</bean>

<bean id="replacementComputeValue" class="a.b.c.ReplacementComputeValue"/>
constructor-arg标签

注入构造器中的参数来创建实例。

package x.y;

public class ThingOne {
	public ThingOne(ThingTwo thingTwo, ThingThree thingThreee) {
		//...
	}
}
<beans>
	<bean id="beanOne" class="x.y.ThingOne">
		<constructor-arg ref="beanTwo"/>
		<constructor-arg ref="beanThree"/>
	</bean>

	<bean id="beanTwo" class="x.y.ThingTwo"/>
	<bean id="beanThree" class="x.y.ThingThree"/>
</beans>

简单的数据类型可以用value属性,Spring无法判断类型,可以用type属性。

package examples;

public class ExampleBean {
	private int years;
	private String ultimateAnswer;

	public ExampleBean(int years, String ultimateAnswer) {
		this.years =years;
		this.ultimateAnswer = ultimateAnswer;
	}
}
<bean id="exampleBean" class="examples.ExampleBean">
	<constructor-arg type="int" value="7500000"/>
	<constructor-arg type="java.lang.String" value="42"/>
</bean>

使用索引注入 index属性,可以解决参数有多个相同类型的问题。

<bean id="exampleBean" class="examples.ExampleBean">
	<constructor-arg index="0" value="7500000"/>
	<constructor-arg index="1" value="42"/>
</bean>

使用构造器参数的名字 name属性,需要使用 @ConstructorProperties 指定名称。

<bean id="exampleBean" class="examples.ExampleBean">
	<constructor-arg name="years" value="7500000"/>
	<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
package examples;

public class ExampleBean {
	@ConstructerProperties({"years", "ultimateAnswer"})
	public ExampleBean(int years, String ultimateAnswer) {
		this.years = years;
		this.ultimateAnswer = ultimateAnswer;
	}
}
property标签

需要有 无参构造器 或者 无参静态工厂setting方法。

<bean id="exampleBean" class="examples.ExampleBean">
    <!-- setter injection using the nested ref element -->
    <property name="beanOne">
        <ref bean="anotherExampleBean"/>
    </property>

    <!-- setter injection using the neater ref attribute -->
    <property name="beanTwo" ref="yetAnotherBean"/>
    <property name="integerProperty" value="1"/>
</bean>

<bean id="anotherExampleBean" class="examples.AnotherBean"/>
<bean id="yetAnotherBean" class="examples.YetAnotherBean"/>
public class ExampleBean {

    private AnotherBean beanOne;

    private YetAnotherBean beanTwo;

    private int i;

    public void setBeanOne(AnotherBean beanOne) {
        this.beanOne = beanOne;
    }

    public void setBeanTwo(YetAnotherBean beanTwo) {
        this.beanTwo = beanTwo;
    }

    public void setIntegerProperty(int i) {
        this.i = i;
    }
}

property标签内可以有bean标签,可用于数据的注入。

<bean id="outer" class="...">
    <!-- instead of using a reference to a target bean, simply define the target bean inline -->
    <property name="target">
        <bean class="com.example.Person"> <!-- this is the inner bean -->
            <property name="name" value="Fiona Apple"/>
            <property name="age" value="25"/>
        </bean>
    </property>
</bean>

property标签内可以有list、set、map、props标签,分别对应List、Set、Map和Properties,可用于容器的数据注入。

<bean id="moreComplexObject" class="example.ComplexObject">
    <!-- results in a setAdminEmails(java.util.Properties) call -->
    <property name="adminEmails">
        <props>
            <prop key="administrator">administrator@example.org</prop>
            <prop key="support">support@example.org</prop>
            <prop key="development">development@example.org</prop>
        </props>
    </property>
    <!-- results in a setSomeList(java.util.List) call -->
    <property name="someList">
        <list>
            <value>a list element followed by a reference</value>
            <ref bean="myDataSource" />
        </list>
    </property>
    <!-- results in a setSomeMap(java.util.Map) call -->
    <property name="someMap">
        <map>
            <entry key="an entry" value="just some string"/>
            <entry key ="a ref" value-ref="myDataSource"/>
        </map>
    </property>
    <!-- results in a setSomeSet(java.util.Set) call -->
    <property name="someSet">
        <set>
            <value>just some string</value>
            <ref bean="myDataSource" />
        </set>
    </property>
</bean>

merge属性可以整合父类与本身的集合。

<beans>
    <bean id="parent" abstract="true" class="example.ComplexObject">
        <property name="adminEmails">
            <props>
                <prop key="administrator">administrator@example.com</prop>
                <prop key="support">support@example.com</prop>
            </props>
        </property>
    </bean>
    <bean id="child" parent="parent">
        <property name="adminEmails">
            <!-- the merge is specified on the child collection definition -->
            <props merge="true">
                <prop key="sales">sales@example.com</prop>
                <prop key="support">support@example.co.uk</prop>
            </props>
        </property>
    </bean>
<beans>

此时的adminEmails的值为:

administrator=administrator@example.com
sales=sales@example.com
support=support@example.co.uk
depends-on属性

depends-on属性表明依赖关系(不一定会引用),这个依赖关系决定了被依赖的bean必定会在依赖bean之前被实例化,反过来,容器关闭时,依赖bean会在被依赖的bean之前被销毁。

<bean id="beanOne" class="ExampleBean" depends-on="manager,accountDao">
    <property name="manager" ref="manager" />
</bean>

<bean id="manager" class="ManagerBean" />
<bean id="accountDao" class="x.y.jdbc.JdbcAccountDao" />
lazy-init属性

设置为true时,使用时才实例化,否则容器启动时实例化。

也可以在beans标签中使用 default-lazy-init 属性。

autowire属性

自动装配,不用显示使用ref。

有四种模式:no(默认)byNamebyTypeconstructor

init-method属性

org.springframework.beans.factory.InitializingBean 接口可以设置初始化工作。它只有以下一个方法,不过不推荐使用。

void afterPropertiesSet() throws Exception;

可以用bean的init-method属性指定初始化方法或者用 @PostConstruct 注解。初始化的方法不含参数。

<bean id="exampleInitBean" class="examples.ExampleBean" init-method="init"/>
public class ExampleBean {
	public void init() {
		//...
	}
}
destroy-method属性

与init-method类似。可以实现 org.springframework.beans.factory.DisposableBean 接口,不过不推荐。也可以用 @PreDestroy 注解或者 bean的destroy-method属性。同样不能带参数。

DisposableBean接口的方法:

void destroy() throws Exception;
default-init-method和default-destroy-method

可以在beans标签中使用这两个属性设置默认方法。

bean的生命周期

Lifecycle接口
public interface Lifecycle {
	void start();
	void stop();
	boolean isRunning();
}

所有Spring管理的对象都可以实现该接口。ApplicationContext接收到启动和停止信号时,它将自动调用上下文内所有Lifecycle的实现。通过委托给 LifecycleProcessor 来做这个工作。

public interface LifecycleProcessor extends Lifecycle {
	void onRefresh();
	void onclose();
}

LifecycleProcessor是Lifecycle的子接口。

public interface Phased {
	int getPhase();
}
public interface SmartLifecycle extends Lifecycle, Phased {
	boolean isAutoStartup();
	void stop(Runnable callback);
}

常规的Lifecycle接口只有在容器上下文显示调用start/stop方法时,都会去回调Lifecycle的实现类的start/stop方法,并不意味着上下文刷新时自动启动。可以用SmartLifecycle解决。

stop通知在销毁前不能保证到达,在常规关闭时,所有生命周期bean将首先收到停止通知,然后才传播一般的销毁回调,但是,在上下文生命周期内的热刷新或中止刷新尝试时,只调用销毁方法。

getPhase()默认返回0,数值越小越先启动,越后停止。

DefaultLifecycleProcessor是LifecycleProcessor的默认实现,将等待每个阶段中的对象组的超时值来调用callback的run()方法,默认的每个阶段超时为30秒。可以通过以下方法修改:

<bean id="lifecycleProcessor" class="org.springframework.context.support.DefaultLifecycleProcessor">
    <!-- timeout value in milliseconds -->
    <property name="timeoutPerShutdownPhase" value="10000"/>
</bean>

非Web应用程序关闭Spring IoC容器

import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public final class Boot {

    public static void main(final String[] args) throws Exception {
        ConfigurableApplicationContext ctx = new ClassPathXmlApplicationContext("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...
    }
}

向JVM注册一个关闭钩子,确保正常关机,并调用singleton bean上相关销毁方法,以便释放所有资源。仍然必须正确配置和实现这些销毁回调。

Aware

能够获取自身在Spring容器中的一些属性。

public interface ApplicationContextAware {
	void setApplicationContext(ApplicationContext applicationContext) throws BeansException;
}
public interface BeanNameAware {
	void setBeanName(String name) throws BeansException;
}

例如applicationContextAware为bean的IoC容器上下文,name为bean的id。

继承

使用parent属性。

<bean id="inheritedTestBean" abstract="true"
        class="org.springframework.beans.TestBean">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>

<bean id="inheritsWithDifferentClass"
        class="org.springframework.beans.DerivedTestBean"
        parent="inheritedTestBean" init-method="initialize">  
    <property name="name" value="override"/>
    <!-- the age property value of 1 will be inherited from parent -->
</bean>

如果父bean没有指定类,则一定要显式将父bean标记为抽象。

<bean id="inheritedTestBeanWithoutClass" abstract="true">
    <property name="name" value="parent"/>
    <property name="age" value="1"/>
</bean>

<bean id="inheritsWithClass" class="org.springframework.beans.DerivedTestBean"
        parent="inheritedTestBeanWithoutClass" init-method="initialize">
    <property name="name" value="override"/>
    <!-- age will inherit the value of 1 from the parent bean definition-->
</bean>

被标志为抽象的bean将不能实例化,只能作为一个模板。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值