0    Spring课程
0.1    Spring入门篇  目录

 https://www.cnblogs.com/1446358788-qq/articles/13070140.html

 

 

 

1    Spring核心
1.1    Spring  IOC(控制反转)原理

归纳总结:

控制反转的原理之一:依赖倒置原则

依赖倒置原则:高层模块不能依赖底层模块,他们依赖他们共同的接口;

控制反转容器:用configuration替代了多个new 对象的步骤,提高了编程效率;

控制反转优点:

 

1    增加了代码的可维护性,节约了修改成本;

2    省略了非必要new对象的步骤,提高了开发效率;

3    提高不同分组的协同合作,成倍提高开发效率;

 

 


转自:https://www.zhihu.com/question/23277575/answer/169698662


要了解控制反转( Inversion of Control ), 我觉得有必要先了解软件设计的一个重要思想:依赖倒置原则(Dependency Inversion Principle )

什么是依赖倒置原则?假设我们设计一辆汽车:先设计轮子,然后根据轮子大小设计底盘,接着根据底盘设计车身,最后根据车身设计好整个汽车。这里就出现了一个“依赖”关系:汽车依赖车身,车身依赖底盘,底盘依赖轮子。

 

这样的设计看起来没问题,但是可维护性却很低。假设设计完工之后,上司却突然说根据市场需求的变动,要我们把车子的轮子设计都改大一码。这下我们就蛋疼了:因为我们是根据轮子的尺寸设计的底盘,轮子的尺寸一改,底盘的设计就得修改;同样因为我们是根据底盘设计的车身,那么车身也得改,同理汽车设计也得改——整个设计几乎都得改!

我们现在换一种思路。我们先设计汽车的大概样子,然后根据汽车的样子来设计车身,根据车身来设计底盘,最后根据底盘来设计轮子。这时候,依赖关系就倒置过来了:轮子依赖底盘, 底盘依赖车身, 车身依赖汽车。

 

这时候,上司再说要改动轮子的设计,我们就只需要改动轮子的设计,而不需要动底盘,车身,汽车的设计了。

这就是依赖倒置原则——把原本的高层建筑依赖底层建筑“倒置”过来,变成底层建筑依赖高层建筑。高层建筑决定需要什么,底层去实现这样的需求,但是高层并不用管底层是怎么实现的。这样就不会出现前面的“牵一发动全身”的情况。


 

 

控制反转(Inversion of Control) 就是依赖倒置原则的一种代码设计的思路。具体采用的方法就是所谓的依赖注入(Dependency Injection)。其实这些概念初次接触都会感到云里雾里的。说穿了,这几种概念的关系大概如下:

 

 

为了理解这几个概念,我们还是用上面汽车的例子。只不过这次换成代码。我们先定义四个Class,车,车身,底盘,轮胎。然后初始化这辆车,最后跑这辆车。代码结构如下:

 

这样,就相当于上面第一个例子,上层建筑依赖下层建筑——每一个类的构造函数都直接调用了底层代码的构造函数。假设我们需要改动一下轮胎(Tire)类,把它的尺寸变成动态的,而不是一直都是30。我们需要这样改:

由于我们修改了轮胎的定义,为了让整个程序正常运行,我们需要做以下改动:

 

由此我们可以看到,仅仅是为了修改轮胎的构造函数,这种设计却需要修改整个上层所有类的构造函数!在软件工程中,这样的设计几乎是不可维护的——在实际工程项目中,有的类可能会是几千个类的底层,如果每次修改这个类,我们都要修改所有以它作为依赖的类,那软件的维护成本就太高了。

所以我们需要进行控制反转(IoC),及上层控制下层,而不是下层控制着上层。我们用依赖注入(Dependency Injection)这种方式来实现控制反转。所谓依赖注入,就是把底层类作为参数传入上层类,实现上层类对下层类的“控制”。这里我们用构造方法传递的依赖注入方式重新写车类的定义:

 

这里我们再把轮胎尺寸变成动态的,同样为了让整个系统顺利运行,我们需要做如下修改:

 

看到没?这里我只需要修改轮胎类就行了,不用修改其他任何上层类。这显然是更容易维护的代码。不仅如此,在实际的工程中,这种设计模式还有利于不同组的协同合作和单元测试:比如开发这四个类的分别是四个不同的组,那么只要定义好了接口,四个不同的组可以同时进行开发而不相互受限制;而对于单元测试,如果我们要写Car类的单元测试,就只需要Mock一下Framework类传入Car就行了,而不用把Framework, Bottom, Tire全部new一遍再来构造Car。

这里我们是采用的构造函数传入的方式进行的依赖注入。其实还有另外两种方法:Setter传递接口传递。这里就不多讲了,核心思路都是一样的,都是为了实现控制反转

 

 

 

看到这里你应该能理解什么控制反转和依赖注入了。那什么是控制反转容器(IoC Container)呢?其实上面的例子中,对车类进行初始化的那段代码发生的地方,就是控制反转容器。

 

显然你也应该观察到了,因为采用了依赖注入,在初始化的过程中就不可避免的会写大量的new。这里IoC容器就解决了这个问题。这个容器可以自动对你的代码进行初始化,你只需要维护一个Configuration(可以是xml可以是一段代码),而不用每次初始化一辆车都要亲手去写那一大段初始化的代码。这是引入IoC Container的第一个好处。

IoC Container的第二个好处是:我们在创建实例的时候不需要了解其中的细节。在上面的例子中,我们自己手动创建一个车instance时候,是从底层往上层new的:

 

这个过程中,我们需要了解整个Car/Framework/Bottom/Tire类构造函数是怎么定义的,才能一步一步new/注入。

而IoC Container在进行这个工作的时候是反过来的,它先从最上层开始往下找依赖关系,到达最底层之后再往上一步一步new(有点像深度优先遍历):

 

这里IoC Container可以直接隐藏具体的创建实例的细节,在我们来看它就像一个工厂:

 

我们就像是工厂的客户。我们只需要向工厂请求一个Car实例,然后它就给我们按照Config创建了一个Car实例。我们完全不用管这个Car实例是怎么一步一步被创建出来。

实际项目中,有的Service Class可能是十年前写的,有几百个类作为它的底层。假设我们新写的一个API需要实例化这个Service,我们总不可能回头去搞清楚这几百个类的构造函数吧?IoC Container的这个特性就很完美的解决了这类问题——因为这个架构要求你在写class的时候需要写相应的Config文件,所以你要初始化很久以前的Service类的时候,前人都已经写好了Config文件,你直接在需要用的地方注入这个Service就可以了。这大大增加了项目的可维护性且降低了开发难度。

 

这里只是很粗略的讲了一下我自己对IoC和DI的理解。主要的目的是在于最大限度避免晦涩难懂的专业词汇,用尽量简洁,通俗,直观的例子来解释这些概念。如果让大家能有一个类似“哦!原来就是这么个玩意嘛!”的印象,我觉得就OK了。想要深入了解的话,可以上网查阅一些更权威的资料。这里推荐一下 Dependency injection Inversion of Control Containers and the Dependency Injection pattern 这两篇文章,讲的很好很详细。

 

 

 

 

 

2    Spring  代码演练
2.1    代码演练  依赖注入两种注入方式

 

1    依赖注入的两种注入方式

2    依赖注入的两种注入方式代码实现

3    依赖注入两种注入方式的区别及优缺点

4    如何解决这个问题

5    引用链接

 

 

 

1    依赖注入的两种注入方式

依赖注入可以分为set注入和构造函数注入
set注入需要注意:注入bean的时候,bean的名字 要和 实体类起的类名相同。

2    依赖注入的两种注入方式代码实现


1  依赖注入的实现方式:

实现类:

 

package com.springnovel.payment.springmixed;

import java.math.BigDecimal;

import org.springframework.beans.factory.annotation.Required;

import com.springnovel.dao.IOrderDao;
import com.springnovel.perfectlogger.ILogger;

/**
 * @author weijingli
 *
 */
public class PaymentAction_SetInjection {
    
    private ILogger logger;


    public PaymentAction_SetInjection(ILogger logger ) {
        super();
        this.logger = logger;
    }


    
    public void pay(BigDecimal payValue){
        logger.log("开始支付,支付金额为:"+payValue);
        logger.log("支付结束;");
    }
    
    
    

}

 

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

<!--     使用了<constructor-arg>标签,指定了ServerLogger作为PaymentAction构造函数的入参: -->
    <bean id="paymentAction_setInjection" class="com.springnovel.payment.springmixed.PaymentAction_SetInjection">
        <constructor-arg ref="serverLogger"></constructor-arg>
    </bean>
    
    <bean id="serverLogger" class="com.springnovel.perfectlogger.ServerLogger"/>

        

</beans>

ServerLogger类:

package com.springnovel.perfectlogger;

public class ServerLogger implements ILogger{

    @Override
    public void log(String logInfo) {
        System.out.println("服务器打印开始:"+logInfo);
    }

}

 

 

 

 


2  set注入的实现方式:
实现类

 

package com.springnovel.payment.springmixed;

import java.math.BigDecimal;

import org.springframework.beans.factory.annotation.Required;

import com.springnovel.dao.IOrderDao;
import com.springnovel.perfectlogger.ILogger;

public class PaymentAction_SetInjection {
    
    private IOrderDao orderDao;


    public IOrderDao getOrderDao() {
        return orderDao;
    }

    public void setOrderDao(IOrderDao orderDao) {
        this.orderDao = orderDao;
    }

    public void updateOrderAfterPayment(String orderId){
        orderDao.updateOrderAfterPayment(orderId);
    }

}

 

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

<!--     使用了<property>标签,set入参: -->
    <bean id="paymentAction_setInjection" class="com.springnovel.payment.springmixed.PaymentAction_SetInjection">
        <property name="orderDao" ref="orderDao"/>
    </bean>
    
    
    <bean id="orderDao" class="com.springnovel.dao.OrderDao"/>
        

</beans>

dao类

package com.springnovel.dao;

public class OrderDao implements IOrderDao {
    


    @Override
    public void deleteOrder(String orderId) {
        // TODO Auto-generated method stub
        System.out.println("删除订单成功,本次删除订单号为:"+orderId);
    }

    @Override
    public void updateOrderAfterPayment(String orderId) {
        // TODO Auto-generated method stub
        System.out.println("订单支付成功,以修改订单"+orderId+"状态为已支付!");
        
    }

}

 

3    依赖注入两种注入方式的区别及优缺点

 区别:

  • Constructor注入能够强制要求调用者注入构造函数中的所有参数,否则在容器初始化时就会失败;但是如果要注入的对象过多,就会导致构造函数过于庞大。
  • Setter注入,类似于Builder模式,将原本庞大的构造函数,拆解为了一个小的构造函数和许多个set方法。setter注入不能保证对象一定会被注入,但是可以使用@Required注解,强制要求使用者注入对象,否则在容器初始化时就会报错。

 

 

4    如何解决这个问题

解决方法:set注入方式添加required注解。 

开启Spring注解的功能:

payment.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"
  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-2.5.xsd">

<!--     使用了<constructor-arg>标签,指定了ServerLogger作为PaymentAction构造函数的入参: -->
<!--     <bean id="paymentActionMixed" class="com.springnovel.payment.springmixed.PaymentActionMixed">
        <constructor-arg ref="serverLogger"></constructor-arg>
        <constructor-arg ref="orderDao"></constructor-arg>
    </bean> -->

    
<!--     使用了<property>标签,set入参: -->
    <bean id="paymentAction_setInjection" class="com.springnovel.payment.springmixed.PaymentAction_SetInjection">
<!--          <property name="serverLogger" ref="serverLogger"/> -->
<!--          <property name="orderDao" ref="orderDao"/> -->
    </bean>
    
    
    <bean id="serverLogger" class="com.springnovel.perfectlogger.ServerLogger"/>
    <bean id="orderDao" class="com.springnovel.dao.OrderDao"/>
    
    <context:annotation-config/>
<!--     <context:component-scan base-package="com.springnovel.perfectlogger"></context:component-scan> -->
</beans>

 

实体类:PaymentAction_SetInjection.java(红色标注部分)

private ILogger serverLogger;
    private IOrderDao orderDao;
    
    @Required
    public void setServerLogger(ILogger serverLogger) {
        this.serverLogger = serverLogger;
    }

    public void setOrderDao(IOrderDao orderDao) {
        this.orderDao = orderDao;
    }

这样一启动服务器就会直接报错,避免了生产运行过程中的隐形bug

 

 

 

5    引用链接

本文参考文章连接:

https://zhuanlan.zhihu.com/p/29426019

项目本地路径:

F:\xiangmu3\Xin\FuQiang\Spring

项目百度云路径:

链接:https://pan.baidu.com/s/1VrIHyaGfogAmPDZ8Vsw7vg
提取码:ewgv

 

 

 

2.2    代码演练  为何需要依赖注入

0    总结

1    代码实现之为何需要依赖注入

2    代码实现之工厂模式和依赖注入 实现代码及优缺点

3    代码实现之如何进行单元测试

4    引用链接

 

 

0    总结

a    为何使用依赖注入

I  使用依赖注入对于需求变更不在需要大量的修改代码,简化了工程量

II    使用依赖注入可以用高内聚低耦合的方式实现代码

III   使用依赖注入可以在数据库发生故障或者项目进度需要时,进行单元测试,节省人力成本

IIII  与工厂模式创建对象相比,他不用每次都创建对象,节省了大量的内存

 

 

 

 

1    为何需要依赖注入

 需求a:  电商项目需要在支付订单接口实现打印日志到文件上的功能,生产有问题方便排查

解决方案:

支付订单类:(详细代码下载见底部)https://pan.baidu.com/s/1m0vDEKOLE5YCry93lubYMA

package com.springnovel.payment.withoutspring;

import java.math.BigDecimal;

import com.springnovel.perfectlogger.Filelogger;
import com.springnovel.perfectlogger.ILogger;

/**
 * 实现功能:日志支付接口打印日志
 * @author weijingli
 * 特点:ILogger 有多个实现类
 * FileLogger
 * ConsoleLogger
 * ServerLogger
 * 
 * 本类缺点:如果将日志打印到本地变更为打印到日志服务器,所有涉及日志的创建对象部分需要进行全量替换,这种情况下代码不合理
 */
public class PaymentActionV1 {
    
    private ILogger logger = new Filelogger();
    
    //此处使用BigDecimal,支付接口必须使用最精确的结果
    public void pay(BigDecimal payValue){
        logger.log("开始打印支付日志,支付金额为"+payValue);
        //do pay ...
        logger.log("打印支付日志结束");
    }
    

}

 

打印到文件日志 实现类:

package com.springnovel.perfectlogger;

public class Filelogger implements ILogger{

    @Override
    public void log(String logInfo) {
        System.out.println("FileLogger:"+logInfo);
    }

}

 

 

 

需求 b:在a的基础上,我所有的接口都需要实现打印日志功能

解决方案:(代码类似上部代码)

一个月后:

需求 c:日志文件满了,磁盘不够,公司买了新的服务器,以后打印日志到服务器上

解决方案:由于日志接口有文件日志实现类和服务器日志实现类。如果全量变更new对象,需求改动量太大。因此可以使用工厂模式或者依赖注入的方式解决这个问题

 

 

 

 

2    工厂模式和依赖注入 实现代码及优缺点

工厂模式解决上述问题

支付订单类

package com.springnovel.payment.withoutspring;

import java.math.BigDecimal;

import com.springnovel.perfectlogger.ILogger;

/**
 * 实现功能:日志打印的功能
 * @author weijingli
 * 功能优点:可自由切换打印日志到服务器或者本地路径,只需要修改工厂类:loggerFactory即可
 * 功能缺点:    1    工厂类每次都new一个新对象,是不是很浪费,能不能做成单例的,甚至是做成单例和多例是可以配置;
 *              2    如果有这种需求:支付信息比较多而且比较敏感,日志要打印到远程服务器,其他信息都打印到本地,怎么实现;
 */
public class PaymentActionV2 {
    
    private ILogger logger = LoggerFactory.createLogger(); 
    
    public void pay(BigDecimal payValue){
        logger.log("支付开始:"+payValue);
        //此处省略一亿字
        logger.log("支付结束:");
    }

}

 

工厂类:

package com.springnovel.payment.withoutspring;

import com.springnovel.perfectlogger.Filelogger;
import com.springnovel.perfectlogger.ILogger;
import com.springnovel.perfectlogger.ServerLogger;

public class LoggerFactory {
    
    private static ILogger logger = new ServerLogger();
    
    //工厂类的方法静态为好,被调用
    public static ILogger createLogger(){
        return logger;
    }
}

 

 

 

依赖注入方式解决上述问题:

支付类依赖日志类,通过payment.xml将日志类注入到支付类即可

支付订单类:

package com.springnovel.payment.springmixed;

import java.math.BigDecimal;

import com.springnovel.perfectlogger.ILogger;

//使用spring的payment.xml方式将log注入到本类中
public class PaymentActionMixed {
    
    private ILogger logger;
    
    
    /**
     * 此处要记,如果注入,构造方法参数必须把注入的类加进去
     * @param logger
     */
    //通过构造方法将logger传入本类
    public PaymentActionMixed(ILogger logger) {
        super();
        this.logger=logger;
        // TODO Auto-generated constructor stub
    }

    public void pay(BigDecimal payValue){
        logger.log("开始支付,支付金额为:"+payValue);
        logger.log("支付结束;");
    }

}

 

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

<!--     使用了<constructor-arg>标签,指定了ServerLogger作为PaymentAction构造函数的入参: -->
    <bean id="paymentActionMixed" class="com.springnovel.payment.springmixed.PaymentActionMixed">
        <constructor-arg ref="serverLogger"/>
    </bean>
    
    <bean id="serverLogger" class="com.springnovel.perfectlogger.ServerLogger"/>

        

</beans>

 

测试demo:

package com.springnovel.test;

import java.math.BigDecimal;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.springnovel.payment.springmixed.PaymentActionMixed;
import com.springnovel.payment.withoutspring.PaymentActionV1;
import com.springnovel.payment.withoutspring.PaymentActionV2;

public class PaymentTest {
    
    @Test
    public void testPaymentActionV1(){
        PaymentActionV1 pav1 = new PaymentActionV1();
        pav1.pay(new BigDecimal(1));//此处传参应为bigdecimal类型
    }
    
    @Test
    public void testPaymentActionV2(){
        PaymentActionV2 pav2 = new PaymentActionV2();
        pav2.pay(new BigDecimal(2));
    }
    
    /**
     * 此处需要记录
     */
    @Test
    //此处要加载payment.xml文件 和 得到bean对象呀
    public void testPaymentActionMixed(){
        ApplicationContext context = new ClassPathXmlApplicationContext("payment.xml");
        PaymentActionMixed pam = (PaymentActionMixed) context.getBean("paymentActionMixed");
        pam.pay(new BigDecimal(7));
        
    }
    

}

 

工厂类缺点:浪费内存

 

 

 

 

 3    如何进行单元测试

问题a:数据库挂了,我要测试业务逻辑删除订单部分,代码如何实现?

测试类:

package com.springnovel.test;

import java.math.BigDecimal;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.springnovel.dao.IOrderDao;
import com.springnovel.order.springxml.OrderAction;
import com.springnovel.payment.springmixed.PaymentActionMixed;
import com.springnovel.payment.withoutspring.PaymentActionV1;
import com.springnovel.payment.withoutspring.PaymentActionV2;

public class OrderTest {
    
    
    
    @Test
    public void testDeleteOrder(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("order.xml");
        OrderAction oa = (OrderAction)ac.getBean("orderAction");
        oa.deleteOrder("12345");
    }
    
    

}

 

 

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

<!--     使用了<constructor-arg>标签,指定了ServerLogger作为PaymentAction构造函数的入参: -->
    <bean id="orderAction" class="com.springnovel.order.springxml.OrderAction">
        <constructor-arg ref="orderDao"/>
    </bean>
    
    <bean id="orderDao" class="com.springnovel.dao.OrderDao"/>

        

</beans>

 

 

实现类:

package com.springnovel.order.springxml;

import com.springnovel.dao.IOrderDao;

/*
 * 单元测试案例:
 * 如果要测试逻辑部分,可以使用此处直接测试 
 * 
 * 功能:订单删除,要求采用spring方式,不连接数据库,就能删除数据
 */
public class OrderAction {
    
    private IOrderDao orderDao;
    
    
    
    public OrderAction(IOrderDao orderDao) {
        super();
        // TODO Auto-generated constructor stub
        this.orderDao = orderDao;
    }



    public void deleteOrder(String orderId){
        
        orderDao.deleteOrder(orderId);
        
    }
    

}

 

 

 

4    引用链接

本文参考文章连接:

https://zhuanlan.zhihu.com/p/29426019

项目本地路径:

F:\xiangmu3\Xin\FuQiang\Spring

项目百度云路径:

https://pan.baidu.com/s/1m0vDEKOLE5YCry93lubYMA

提取码:kx0s

 

 

 

3    Spring  报错
3.1    Spring错误:Exception encountered during context initialization

1  完整报错:

2  错误分析:

3  解决方法:

 

 

1  完整报错:

警告: Exception encountered during context initialization - cancelling refresh attempt: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'injectionServiceImpl' defined in file [F:\xiangmu3\Xin\FuQiang\Spring\ddwei-dao\target\classes\com\imooc\beanannotation\injection\service\InjectionServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.imooc.bean.ioc.interfaces.InjectionDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'injectionServiceImpl' defined in file [F:\xiangmu3\Xin\FuQiang\Spring\ddwei-dao\target\classes\com\imooc\beanannotation\injection\service\InjectionServiceImpl.class]: Unsatisfied dependency expressed through constructor parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.imooc.bean.ioc.interfaces.InjectionDao' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
    at org.springframework.beans.factory.support.ConstructorResolver.createArgumentArray(ConstructorResolver.java:749)
    at org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:189)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1193)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1095)
   

 

2  错误分析:

expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: 

通过分析报错部分:依赖注入的注解,期望至少有一个类是自动装配达标。
说明是没有添加注解呗,通过百度搜索,很多报这种类型的错误的都是bean没有加注解。

分析我本地的报错:
service 引用的dao类有两个package,一个有注解,一个没有,我的package引用的是没有注解的那个

 

3  解决方法:

更新package即可

 

 

 

3.2    Spring  错误  Bean property 'serverLogger' is not writable or has an invalid setter method.

使用spring set注入方式,报错如上:类的属性有一个非法的set 方法。

 

经查询:

payment.xml如下:

<!--     使用了<property>标签,set入参: -->
    <bean id="paymentAction_setInjection" class="com.springnovel.payment.springmixed.PaymentAction_SetInjection">
         <property name="serverLogger" ref="serverLogger"/>
         <property name="orderDao" ref="orderDao"/>
    </bean>
    
    
    <bean id="serverLogger" class="com.springnovel.perfectlogger.ServerLogger"/>
    <bean id="orderDao" class="com.springnovel.dao.OrderDao"/>

 

PaymentAction_SetInjection如下:

    private ILogger logger;
    private IOrderDao orderDao;
    
    public void setLogger(ILogger logger) {
        this.logger = logger;
    }

    public void setOrderDao(IOrderDao orderDao) {
        this.orderDao = orderDao;
    }

 

知:set方法的name值必须  和 实体类的声明的变量名一致。

PaymentAction_SetInjection修改方法如下(红色部分):

   private ILogger serverLogger;
    private IOrderDao orderDao;
    

    public void setServerLogger(ILogger serverLogger) {
        this.serverLogger = serverLogger;
    }

    public void setOrderDao(IOrderDao orderDao) {
        this.orderDao = orderDao;
    }

 

 

 

 

4    Spring  概念
4.1    Spring  解惑  @RunWith的作用

@RunWith就是一个运行器

@RunWith(JUnit4.class)就是指用JUnit4来运行

 

4.2    Spring  解惑  spring-xml配置文件编译

问题:maven项目中,以前编写spring-xml总是不编译。

解决方案共有两种:

1  将配置文件xml放在main文件夹下的resource文件夹,和java文件夹平级。

2  右键项目==》build path==》config buildpath==》 source==》add folder==》添加xml所在resource文件夹==》ok确认即可

 

 

 

4.3    dao、domain、service、web 分别是java里面的什么概念?为什么总放在一起

web-->domain-->service-->dao

这是mvc结构, web主要是 客户端网页,是表层的东西,可接收和返回数据给用户
domain主控制层,是用户与数据库交互的核心中转站,控制用户数据收集,控制请求转向
service是 业务逻辑层,处理数据 逻辑,验证数据,
dao是持久层,读写数据库
web发出请求---domain接收控制数据转向(可以返回也可以进入service)---service验证数据正确性或者是否符合业务要求---dao存入,读出,依次返回

 

 

4.4    DO、PO、BO、DTO、VO等概念
  • POJO  全称为:Plain Ordinary Java Object,普通的 java 对象,一般用在数据层映射到数据库表的类,类的属性与表字段一一对应
     
  • PO  全称为:Persistant Object,持久化对象,与数据库结构映射的实体,数据库中的一条数据即为一个 PO 对象
     
  • BO  全称为:Business Object,业务对象,主要作用是把业务逻辑封装成一个对象,这个对象可以包括一个或多个其它对象,比如一个简历 BO 中有教育经历,工作经历,社会关系等 BO 对象
     
  • DTO  全称为:Data Transfer Object,数据传输对象,比如一张表有 100 个字段,那么对应的 PO 就有100 个属性(大多数情况下,DTO内部的数据结构来自多个表)但 view 层只需要显示 10 个字段,没有必要把整个 PO 对象传递到 client,这时我们就可以用只有这 10 个属性的 DTO 来传输给 client,这样也不会暴露 server 端表结构,到达客户端后,如果这个对象来对应页面显示,它的身份就转为 VO
     
  • VO  全称为:View Object,主要对应页面展示的数据对象,一般继承自 PO,可以添加 PO 中没有的字段,用来逻辑处理以及其它消息存储
     
  • DO  全称为:Domain Object,领域对象,从现实世界中抽象出的业务实体,一般还包含 ORM 映射
     
  • DAO  全称为:Data Access Object,数据访问对象,一般所说的 DAO 层,用于连接数据库与外层之间的桥梁,并持久化数据层对象
     
  • JavaBean 是一种 Java 语言写成的可重用组建,它的规范必须符合特定的约定:
    • 这个类必须有一个公共的缺省构造函数
    • 这个类的属性用 getter 和 setter 访问
    • 这个类可被序列化

模型

  • 用户发出请求,表单的数据层被匹配为 VO
  • 展示层把 VO 转换为服务层对应方法锁要求的 DTO,传输给服务层
  • 服务层首先根据 DTO 的数据构造一个 DO,调用 DO 的业务方法完成具体业务
  • 服务层把 DO 转换为持久层对应的 PO,调用持久层持久化方法,把 PO 传递给它完成持久化操作

转载:https://www.jianshu.com/p/1832575fd79e

 

posted on 2019-03-10 11:06  菜鸟乙  阅读(9136)  评论(0)    收藏  举报