Javaweb-spring的IoC

一.为什么要使用spring框架?

解耦

1.1

如果没有Spring,我们不得不在使用每个类之前,实例化一个对象。当然我们可以用工厂方法来做这件事,就可以集中管理并且让调用者和被调用者之间的耦合更松散。于是需要大量的工厂类,并且在增加或改变接口实现的时候,还需要对工厂进行调整。而Spring就像一个大工厂一样,使用了大量的反射机制来生成需要实例的对象。

除此之外Spring还带来了强大的代理,我们使用的每个注入的对象都是经过代理的增强对象,同时可以使用aop包来定义一些与业务逻辑不相关的切面。增强功能模块的内聚,拆分功能模块和非业务模块。而AOP又是建立在IOP基础之上,因此如果没有Spring,功能模块和非功能模块混在一起,导致逻辑混乱不清晰。

1.2 一个IoC的例子

通常,我们开发的java应用都是由多个类组成,它们之间相互协作来完成特定的业务逻辑。每个对象之间相互联系,导致高度耦合的代码。

package com.spring;

public class Performer {
    private Violin violin;
    public Performer(){
        violin=new Violin();                //与Violin紧密耦合
    }
    public void play(){
        violin.play();
    }
}
class Violin extends Instrument {

    public void play() {
        System.out.println("Violin music!");
    }
}
class Instrument {
    void play(){};
}

上面的代码有个非常明显的问题:Performer在构造函数中创建Violin,这使得Performer与Violin紧密耦合在一起,并且当演奏家需要演奏其他乐器时,就需要改写代码。

package com.spring;

public class Performer {
    private Instrument ins;
    public Performer(Instrument ins){
        this.ins=ins;            
    }
    public void play(){
        ins.play();
    }
}
class Violin extends Instrument {

    public void play() {
        System.out.println("Violin music!");
    }
}
class Instrument {
    void play(){};
}

不同于之前的演奏家,这次的演奏家没有创建乐器,而是通过构造函数将乐器通过构造参数传入。这便是依赖注入的一种:构造器注入。

它不仅能够演奏小提琴,无论是钢琴、大提琴、手风琴等继承了Instrument的子类都能作为参赛传入。

而且它本身并不知道将会演奏什么乐器,这与它无关。这便是依赖注入的好处-------松耦合

<?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">
    <bean id="perform" class="Perform">
        <constructor-arg ref="violin"/>
    </bean>
    <bean id="violin" class="Volin"></bean>
</beans>

1.3配置文件

对于spring架构,Jakarta Commons Logging API (JCL)是强制依赖的。spring将JCL反编译,并使得它们对类可见,从而扩展spring。程序员应该要意识到,所有版本的spring使用同一个logging库:因此迁移是很容易的,因为保证了向下兼容。程序员其实需要做的只是设置spring的某些模块,使其明确地依赖到commons-logging(一个权威的JCL实现包)上,同时使其他模块也在编译时依赖它。另外,spring-core模块就是依赖commons-logging的。

1.3.1开头的xlmns部分

xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:关于初始化bean的格式文件地址                xmlns:xsi:辅助初始化bean

1.3.2xsi:schemaLocation部分

是为上面配置的命名空间指定xsd规范文件,这样你在进行下面具体配置的时候就会根据这些xsd规范文件给出相应的提示,比如说每个标签是怎么写的,都有些什么属性是都可以智能提示的,以防配置中出错而不太容易排查,在启动服务的时候也会根据xsd规范对配置进行校验。但是这里需要为你上面xmlns里面配置的mvc、aop、tx等都配置上xsd规范文件。

二.IoC(Inversion of Control)

2.1什么是IoC

在IoC出现以前,组件之间的协调关系是由程序内部代码来控制的,或者说,以前我们使用New关键字来实现两组间之间的依赖关系的。 这种方式就造成了组件之间的互相耦合。IoC(控制反转)就是来解决这个问题的,它将实现组件间的关系从程序内部提到外部容器来管理。 也就是说,由容器在运行期将组件间的某种依赖关系动态注入组件中。

2.2IoC的实现方式 及 与DI的关系

(1).依赖查找(Dependency Lookup):容器中的受控对象通过容器的API来查找自己所依赖的资源和协作对象。 这种方式虽然降低了对象间的依赖,但是同时也使用到了容器的API,造成了我们无法在容器外使用和测试对象。 依赖查找是一种更加传统的IoC实现方式。

(2).依赖注入(Dependency Injection):这就是DI,字面上理解,依赖注入就是将服务注入到使用它的地方。对象只提供普通的方法让容器去决定依赖关系, 容器全权负责组件的装配,它会把符合依赖关系的对象通过属性(JavaBean中的setter)或者是构造子传递给需要的对象。 相对于IoC而言,依赖注入(DI)更加准确地描述了IoC的设计理念。所谓依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定, 也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。

相对于IoC而言,依赖注入(DI)更加准确地描述了IoC的设计理念。所谓依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定.

2.3.Spring中的IoC与DI:

IoC是Spring的核心,贯穿始终。对于Spring框架来说,就是由Spring来负责控制对象的生命周期和对象间的关系。 Spring中DI有两种实现方式---Setter方式(传值方式)和构造器方式(引用方式)。

Setter方式(传值方式):

spring.xml文件:

JavaBean

构造器方式(引用方式)

见一开始的例子。

注入特殊域的方法:

三.Bean的实例化方式

在Spring中通过配置文件创建对象。 Bean实例化三种方式实现: 

(1)使用类的无参数构造创建,如:

(2)使用静态工厂创建 
  如果一个Bean不能通过new直接实例化,而是通过工厂类的某个静态方法创建的,需要把<bean>class属性配置为工厂类。如:

3)使用实例工厂创建 
  如果一个Bean不能通过new直接实例化,而是通过工厂类的某个实例方法创建的,需要先配置工厂的<bean>标签,然后在需要创建的对象的bean标签的factory-bean属性配置为工厂类对象,factory-method属性配置为产生实例的方法。如:

四.spring的注解开发

https://www.cnblogs.com/xiaoxi/p/5935009.html

4.1@Autowired

@Autowired顾名思义,就是自动装配,其作用是为了消除代码Java代码里面的getter/setter与bean属性中的property。当然,getter看个人需求,如果私有属性需要对外提供的话,应当予以保留。

@Autowired默认按类型匹配的方式,在容器查找匹配的Bean,当有且仅有一个匹配的Bean时,Spring将其注入@Autowired标注的变量中。

其实在启动spring IoC时,容器自动装载了一个AutowiredAnnotationBeanPostProcessor后置处理器,当容器扫描到@Autowied、@Resource或@Inject时,就会在IoC容器自动查找需要的bean,并装配给该对象的属性 

<bean class="org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor"/>  
在使用@Autowired时,首先在容器中查询对应类型的bean,

    如果查询结果刚好为一个,就将该bean装配给@Autowired指定的数据
    
    如果查询的结果不止一个,那么@Autowired会根据名称来查找。
    
    如果查询的结果为空,那么会抛出异常。解决方法时,使用required=false

<context:component-scan/> 扫描指定的包中的类上的注解,常用的注解有:

@Controller 声明Action组件
@Service    声明Service组件    @Service("myMovieLister") 
@Repository 声明Dao组件
@Component   泛指组件, 当不好归类时. 
@RequestMapping("/menu")  请求映射
@Resource  用于注入,( j2ee提供的 ) 默认按名称装配,@Resource(name="beanName") 
@Autowired 用于注入,(srping提供的) 默认按类型装配 
@Transactional( rollbackFor={Exception.class}) 事务管理
@ResponseBody
@Scope("prototype")   设定bean的作用域

就会将这个对象作为Bean注入进spring容器.

<?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-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
    <context:component-scan base-package="AnnotationDemo" />
    <bean id="person" class="AnnotationDemo.Person"/>
    <bean id="nose" class="AnnotationDemo.Nose"/>
    <bean id="eye" class="AnnotationDemo.Eye"/>
</beans>

如果属性找不到我不想让Spring容器抛出异常,而就是显示null,可以吗?可以的,其实异常信息里面也给出了提示了,就是将@Autowired注解的required属性设置为false即可.

4.2@Qualifier(指定注入Bean的名称)

当没有对应的bean时,spring容器会自动寻找实现了指定接口的bean:

但是如果出现两个类同时实现一个接口,但是使用的时候用Autowired注入接口,那么spring就不知道是哪一个JavaBean。

运行同样的程序就会报错

所以,可以用Qualifier(“名称”)来指定要使用哪一个javabea

输出:

4.3@Resource

@Resource注解与@Autowired注解作用非常相似

说一下@Resource的装配顺序:
(1)、@Resource后面没有任何内容,默认通过name属性去匹配bean,找不到再按type去匹配
(2)、指定了name或者type则根据指定的类型去匹配bean
(3)、指定了name和type则根据指定的name和type去匹配bean,任何一个不匹配都将报错

然后,区分一下@Autowired和@Resource两个注解的区别:
(1)、@Autowired默认按照byType方式进行bean匹配,@Resource默认按照byName方式进行bean匹配
(2)、@Autowired是Spring的注解,@Resource是J2EE的注解,这个看一下导入注解的时候这两个注解的包名就一清二楚了

4.4@Service

在类前面加上@Service就相当于自动在配置文件加入bean信息:

@Service
class Mouth {
    public void work() {
        System.out.println("I have a mouth!");
    }
}

相当于:

 <bean id="mouth" class="ServiceDemo.Mouth"/>

若想指定id,则在@Service(“指定的id”).

五.使用注解来构造IoC容器

5.1@Component
@Component是所有受Spring 管理组件的通用形式,@Component注解可以放在类的头上,@Component不推荐使用。

5.2@Controller
@Controller对应表现层的Bean,也就是Action

5.3@Service
@Service对应的是业务层Bean

5.4@ Repository
@Repository对应数据访问层Bean

MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一种业务逻辑、数据、界面显示分离的方法组织代码,将业务逻辑聚集到一个部件里面,在改进和个性化定制界面及用户交互的同时,不需要重新编写业务逻辑。MVC被独特的发展起来用于映射传统的输入、处理和输出功能在一个逻辑的图形化用户界面的结构中。

猜你喜欢

转载自blog.csdn.net/weixin_38967434/article/details/82974017