Spring中IoC初识

Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

IoC:控制反转,控制权的转移,应用程序本身不负责依赖对象的创建和维护,而是由外部容器负责创建和维护。反转即获得依赖对象的过程被反转了,控制被反转后,获得依赖对象的过程由自身管理变为了由IoC容器主动注入。
DI:依赖注入,是IoC的一种实现方式。即是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。

目的:创建对象并且组装对象之间的关系。

Spring注入是指在启动Spring容器加载bean配置的时候,就完成对变量的赋值行为
1.设值注入
2.构造注入

设值注入:property,类中要有set方法
若property中的name属性为injectionDao,其在执行的时候就是调用setInjectionDao()这个方法

构造注入:constructor-arg,类中要有构造方法,且要传入对应的参数
若constructor-arg中的name属性为injectDao,则类中的构造方法的参数名必须为injectDao

//设值注入
<bean id="injectionService" class="com.lmr.spring.ioc.injection.service.InjectionServiceImpl">
    <property name="injectionDao" ref="injectionDao"></property>
</bean>

//构造注入
<bean id="injectionService" class="com.lmr.spring.ioc.injection.service.InjectionServiceImpl">
    <constructor-arg name="injectionDao" ref="injectionDao"></constructor-arg>
</bean>
public class InjectionServiceImpl implements InjectionService{

    private InjectionDao injectionDao;

    //设值注入
//  public void setInjectionDao(InjectionDao injectionDao) {
//      this.injectionDao = injectionDao;
//  }

    //构造器注入
    public InjectionServiceImpl(InjectionDao injectionDao) {
        // TODO Auto-generated constructor stub
        this.injectionDao=injectionDao;
    }

    @Override
    public void save(String arg) {
        // TODO Auto-generated method stub

        //模拟业务操作
        System.out.println("Service层接收数据: "+arg);

        injectionDao.save(arg);

    }

}

Bean的作用域 Scope
参数:
singleton 单例,指一个Bean容器中只存在一份(若对一个Bean实例化两个对象,则前者的内容会被后者覆盖,即两个对象的值都相同,引用的是同一个内存块)
prototype 每次请求(每次使用)创建新的实例,destroy方式不生效
request 每次http请求创建一个实例且仅在当前request内有效
session 同上,每次http请求创建,当前session内有效
global session 基于portlet的web中有效(portlet定义了global session),如果是在web中,同session

测试singleton和prototype作用域

public class BeanScope {

    private int id;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public void print(){
        System.out.println(this.hashCode()+" - - "+this.id);
    }

    public void say(){
        System.out.println("BeanScope say : "+this.hashCode());//通过hashCode()方法来判断通过容器生成的对象是否为同一个对象
    }

}
@Test
public void TestSay(){

    BeanScope beanscope1=super.getBean("beanScope");
    beanscope1.say();
    beanscope1.setId(2);
    beanscope1.print();

    BeanScope beanscope2=super.getBean("beanScope");
    beanscope2.say();
    beanscope2.setId(3);
    beanscope2.print();

    beanscope1.say();
    beanscope1.print();

}
<bean id="beanScope" class="com.lmr.spring.bean.BeanScope" scope="singleton"></bean>

结果:两个对象的hashCode值和id值都一样,引用的是同一内存块

BeanScope say : 858242339
858242339 - - 2
BeanScope say : 858242339
858242339 - - 3
BeanScope say : 858242339
858242339 - - 3
<bean id="beanScope" class="com.lmr.spring.bean.BeanScope" scope="prototype"></bean>

结果:两个对象的hashCode值和id值都不一样,后者没有影响到前者

BeanScope say : 1007653873
1007653873 - - 2
BeanScope say : 836514715
836514715 - - 3
BeanScope say : 1007653873
1007653873 - - 2

Bean的生命周期
定义

graph LR
定义-->初始化
初始化-->使用
使用-->销毁

初始化
1.实现org.springframework.beans.factory.InitializingBean接口,覆盖afterPropertiesSet方法
2.配置init-method
销毁
1.实现org.springframework.beans.factory.DisposableBean接口,覆盖destroy方法
2.配置destroy-method

<bean id="beanLifeCycle" class="com.lmr.spring.bean.BeanLifeCycle" init-method="Start" destroy-method="Stop"></bean>
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;

public class BeanLifeCycle implements InitializingBean,DisposableBean{

    //配置全局默认初始化、销毁方法
    public void defaultInit(){
        System.out.println("Bean Default Init");
    }

    public void defaultDestory(){
        System.out.println("Bean Default Destory");
    }

    //实现InitializingBean、DisposableBean接口
    @Override
    public void afterPropertiesSet() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("Bean Init");
    }

    @Override
    public void destroy() throws Exception {
        // TODO Auto-generated method stub
        System.out.println("Bean Destroy");
    }

    //配置init-method、destroy-method
    public void Start(){
        System.out.println("Bean Start");
    }

    public void Stop(){
        System.out.println("Bean Stop");
    }

}

配置全局默认初始化、销毁方法(去检测Bean中是否有对应的方法,若有则执行,没有也不会报错)

<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="defaultInit" default-destroy-method="defaultDestory">

</beans>

若Bean实现了InitializingBean、DisposableBean接口或者配置了init-method、destroy-method,则全局默认初始化、销毁方法将不起作用,不会执行。若Bean同时实现了InitializingBean、DisposableBean接口又配置了init-method、destroy-method,则按先后顺序执行,先执行接口的方法,再执行配置的方法

Aware
使实现了Aware接口的bean在被初始化之后,可以获取相应资源
ApplicationContextAware
BeanNameAware

public class BeanAware implements BeanNameAware,ApplicationContextAware{

    private String beanname;
    private ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        // TODO Auto-generated method stub
        this.context=arg0;
        System.out.println("BeanAware setApplicationContext : "+context.getBean(beanname).hashCode());
    }

    @Override
    public void setBeanName(String name) {
        // TODO Auto-generated method stub
        this.beanname=name;
        System.out.println("BeanAware name : "+beanname);
    }

}

Bean的自动装配(Autowiring)
参数:
No 不做任何操作
byName 根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配;如果没有找到,则什么都不做
byType 如果容器中存在一个与指定属性类型相同的bean,那么将于该属性自动装配;如果存在多个该类型bean,那么抛出异常,并指出不能使用byType方式进行自动装配;如果没有找到相匹配的bean,则什么事都不发生
Constructor 与byType方式类似,不同之处在于它应用与构造器参数。如果容器中没有找到与构造器参数类型一致的bean,那么抛出异常

<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-autowire="byName">

    <bean id="beanAutowireService" class="com.lmr.spring.bean.BeanAutowireService"></bean>

    <bean id="beanAutowireDao" class="com.lmr.spring.bean.BeanAutowireDao"></bean>

</beans>
public class BeanAutowireService {

    private BeanAutowireDao beanAutowireDao;

    public void setBeanAutowireDao(BeanAutowireDao beanAutowireDao) {
        System.out.println("setBeanAutowireDao");
        this.beanAutowireDao = beanAutowireDao;
    }

//  public BeanAutowireService(BeanAutowireDao beanAutowireDao) {
//      System.out.println("Constructor");
//      this.beanAutowireDao = beanAutowireDao;
//  }

    public void say(String word){

        System.out.println("BeanAutowireService : "+word);
        beanAutowireDao.say(word);

    }

}
@Test
public void testAutowire(){
    BeanAutowireService beanAutowireService=super.getBean("beanAutowireService");
    beanAutowireService.say("hello,Autowire");
}

结果:

setBeanAutowireDao
BeanAutowireService : hello,Autowire
BeanAutowireDao : hello,Autowire

Bean的资源文件的统一接口 Resources
ResourceLoader:资源加载器,所有的ApplicationContext都实现了该接口,可以直接获取资源
classpath:xx/xx/xx.xx 从classpath中加载
file:/xx/xx/xx.xx
http://xx/xx/xx.xx
(none):/xx/xx/xx.xx 依赖于ApplicationContext

public class BeanResource implements ApplicationContextAware{

    private ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        // TODO Auto-generated method stub
        this.applicationContext=arg0;
    }

    public void resource() throws IOException{
        Resource resource=applicationContext.getResource("classpath:config.xml");
//      Resource resource=applicationContext.getResource("file:D:\\coding\\codeworksace\\Spring\\src\\main\\resources\\config.xml");
//      Resource resource=applicationContext.getResource("url:http://docs.spring.io/spring-boot/docs/2.0.0.BUILD-SNAPSHOT/reference/htmlsingle/");
//      Resource resource=applicationContext.getResource("config.xml");


        System.out.println(resource.getFilename());
        System.out.println(resource.contentLength());
        FileInputStream input=new FileInputStream(resource.getFile());
        byte[] bytes=new byte[1024];
        while(input.read(bytes)!=-1){
            System.out.println(new String(bytes));
        }
        input.close();
    }

}

结果:

config.xml
306
<?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-3.0.xsd">

</beans>

注解
@Component是一个通用注解,可用于任何bean
@Repository,@Service,@Controller是更有针对性的注解
@Repository通常用于注解DAO类,即持久层
@Service通常用于注解Service类,即服务层
@Controller通常用于注解Controller类,即控制层(MVC)
引入以上注解时,默认的Bean的id为类名首字母变小写,BeanAnnotation->beanannotation;也可加入参数,参数的值即为Bean的id,@Component(“bean”)

@Scope作用域
默认为singleton
@Scope(“prototype”)

扫描器
过滤器
通过此扫描器,spring会扫描包下面的注解,通过各个注解的规则,来进行bean的自动装配

<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-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:component-scan base-package="com.lmr.spring.beanannotation"></context:component-scan>

</beans>

Bean的自动装配
@Required注解使用于bean属性的setter方法
该注解仅仅表示受影响的bean属性必须在配置时被填充,通过在bean定义或通过自动装配一个明确的属性值

@Autowired注解可用于“传统”的setter方法,也可用于构造器或成员变量
用于成员变量上,就不需要setter方法了
默认情况下,如果因找不到合适的bean将会导致autowiring失败抛出异常,可以通过设置required=false来避免。每个类中只能有一个构造器被标记为required=true
@Autowired的自动注入策略是byType,按类型自动装配

@Qualifier注解
当按类型自动装配可能多个bean实例的情况,使用@Qualifier可以缩小范围,或者指定唯一,也可以用于指定单独的构造器参数或方法参数
其value值为所选bean的id,也可在xml中配置bean的qualifier值

<bean class="com.lmr.spring.beanannotation.injection.dao.InjectionDaoImplOne">
    <qualifier value="daoOne"></qualifier>
</bean>
@Autowired()
@Qualifier("injectionDaoImplOne")
private InjectionDao injectionDao;

//设值注入
@Autowired()
public void setInjectionDao(@Qualifier("injectionDaoImplOne")InjectionDao injectionDao) {
    this.injectionDao = injectionDao;
}

@Autowired 和 @Qualifier 结合使用时,自动注入的策略就从 byType 转变成 byName

@Autowired适用于fields,constructors,multi-argument methods这些允许在参数级别使用@Qualifier注解缩小范围的情况
@Resource使用于成员变量,只有一个参数的setter方法,所以在目标是构造器或一个多参数方法时,最好的方式时使用qualifiers

容器注解
@Bean 标识一个用于配置和初始化一个由SpringIoC容器管理的新对象的方法,类似于XML配置文件中的
属性: name、init-method、destroy-method
@Configuration 配置
通常与@bean公用的注解是@configuration而不是@component。
在方法头加上@bean注解,然后方法返回一个bean实例,完成向springIOC容器中注册一个bean实例。
@Scope 默认是单例的
属性:value 作用域(singleton,prototype,session,request,global session)
proxyMode 代理方式,代理可以采取延迟解析策略(ScopedProxyMode.NO,ScopedProxyMode.INTERFACES,ScopedProxyMode.TARGET_CLASS)

@Configuration
public class AppConfig { //这里使用@Configuration注解,标识这个类相当于一个注册文件
    @Bean
    public MyService myService() { 
        return new MyServiceImpl();
    }
}
<beans>
    <bean id="myService" class="com.acme.services.MyServiceImpl"/>
</beans>

加载外部资源文件
一种是Xml获取,一种是Java注解方式获取

<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-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config></context:annotation-config>
    <context:property-placeholder location="classpath:/jdbc.properties" />

    <bean class="org.springframework.jdbc.datasource.DiverManagerDataSource">
        <property name="url" value="${jdbc.url}"></property>
        <property name="username" value="${jdbc.username}"></property>
        <property name="password" value="${jdbc.password}"></property>
    </bean>

</beans>

@ImportResource
参数:value为声明properties的xml文件的路径
使用@Value(“${}”)给类中属性赋值

@Configuration
@ImportResource(value = { "classpath:/resourceconfig.xml" })
public class StoreConfig {

    @Value("${jdbc.username}")
    private String username;

    @Value("${jdbc.password}")
    private String password;

    @Value("${jdbc.url}")
    private String url;

    @Bean(name="diverManager")
    public DiverManager getDiverManager(){
        return new DiverManager(username, password, url);
    }

}
//resourceconfig.xml
<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-3.0.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config></context:annotation-config>
    <context:property-placeholder location="classpath:/jdbc.properties" />

</beans>

JSR注解

使用JSR-250的注解
@Resource
默认的名称是从属性名或者setter方法得出
可通过name属性来将其解析为一个bean的名称,这是由ApplicationContext中的CommonAnnotationBeanPostProcessor发现并处理的
@PostConstruct 初始化方法
@PreDestroy 销毁方法
需要先注册CommonAnnotationBeanPostProcessor类;效果与xml配置的init-method ,destroy-method一致。

使用JSR-330标准注解(依赖注入注解)
扫描方式与Spring注解一致,需要依赖javax.inject包

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

@Inject 等效于@Autowired, 可以使用于类,属性,方法,构造器
@Named 如果想使用特定名称进行依赖注入,使用@Named
@Named与@Component是等效的,通常与@Inject一起使用,跟@Qualifier类似

@Service
public class JsrService {

//  @Resource
//  @Autowired
    @Inject
    private JsrDao jsrDao;

//  @Resource
    public void setJsrDao(@Named("jsrDao")JsrDao jsrDao) {
        this.jsrDao = jsrDao;
    }

    public void save(String word){
        System.out.println("JsrService : "+word);
        jsrDao.save(word);
    }

    @PostConstruct
    public void init(){
        System.out.println("JsrService init !");
    }

    @PreDestroy
    public void destory(){
        System.out.println("JsrService destory !");
    }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值