Spring 依赖注入详解

一、IOC 依赖注入

1.什么是Spring的依赖注入

依赖注入,是IOC的一个方面,是个通常的概念,它有多种解释。这概念是说你不用创建对象,而只需要描述它如何被创建。你不在代码里直接组装你的组件和服务,但是要在配置文件里描述哪些组件需要哪些服务,之后一个容器(IOC容器)负责把他们组装起来。

2. IOC的作用

降低程序间的耦合(依赖关系)
依赖关系的管理:
以后都交给spring来维护
在当前类需要用到其他类的对象,由spring为我们提供,我们只需要在配置文件中说明依赖关系的维护,就称之为依赖注入。

3.依赖注入的方式

能注入的数据:有三类

  • 基本类型和String。
  • 其他bean类型(在配置文件中或者注解配置过的bean)。
  • 复杂类型/集合类型。

注入的方式:有三种

  • 使用构造函数提供。
  • 使用set方法提供。
  • 使用注解提供。

1)构造函数注入

顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置的方式,让 spring 框架来为我们注入。

说明:

  • 使用的标签:constructor-arg
  • 标签出现的位置:bean标签的内部
  • 标签中的属性:
    • type:用于指定要注入的数据的数据类型,该数据类型也是构造函数中某个或某些参数的类型。
    • index:用于指定要注入的数据给构造函数中指定索引位置的参数赋值。索引的位置是从0开始。
    • name:用于指定给构造函数中指定名称的参数赋值。
    • value:用于提供基本类型和String类型的数据
    • ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象
  • 优势:
    在获取bean对象时,注入数据是必须的操作,否则对象无法创建成功。
  • 弊端:
    改变了bean对象的实例化方式,使我们在创建对象时,如果用不到这些数据,也必须提供。
<!--默认构造器方式-->
<bean id="user" class="com.kuang.pojo.User">
  <property name="name" value="张三"/>
</bean>

<!--通过有参构造创建对象。方式一:下标赋值-->
<bean id="user" class="com.kuang.pojo.User">
  <constructor-arg index="0" value="jerry"/>
</bean>

<!--通过有参构造创建对象。方式二:类型创建,不建议使用-->
<bean id="user" class="com.kuang.pojo.User">
  <constructor-arg type="java.lang.String" value="jarry"/>
</bean>

<!--通过有参构造创建对象。方式三:通过参数名,推荐使用-->
<bean id="user" class="com.kuang.pojo.User">
  <constructor-arg name="name" value="jarry"/>
  <constructor-arg name="birthday" ref="now"/>
</bean>
<!-- 配置一个日期对象 -->
<bean id="now" class="java.util.Date"></bean>

2)Set方式注入

  • 顾名思义,就是在类中提供需要注入成员的 set 方法。
    • 依赖:bean对象的依赖于容器
    • 注入:bean对象中的所有属性,有容器来注入。

set方法注入【常用】

  • 涉及的标签:property
  • 出现的位置:bean标签的内部
  • 标签的属性
    • name:用于指定注入时所调用的set方法名称
    • value:用于提供基本类型和String类型的数据
    • ref:用于指定其他的bean类型数据。它指的就是在spring的Ioc核心容器中出现过的bean对象。
  • 优势:
    创建对象时没有明确的限制,可以直接使用默认构造函数。
  • 弊端:
    如果有某个成员必须有值,则获取对象是有可能set方法没有执行。
<bean id="accountService2" class="com.itheima.service.impl.AccountServiceImpl2">
    <property name="name" value="tom" ></property>
    <property name="age" value="23"></property>
    <property name="birthday" ref="now"></property>
</bean>

3)复杂类型的注入

顾名思义,就是给类中的集合成员传值,它用的也是set方法注入的方式,只不过变量的数据类型都是集合。

注入的有:数组,List,Set,Map,Properties,null。

代码如下:

Person类

public class Person {

    private String name;
    private int age;

    //getting、setting

    @Override
    public String toString() {
        return "Person{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

Student类

public class Student {

    private String name;
    private Person person;
    private String[] arr;
    private List<String> myList;
    private Map<String,String> myMap;
    private Set<String> mySet;
    private String wife;
    private Properties myPro;

    @Override
    public String toString() {
        return "Student{" +
                "name='" + name + '\'' +
                ", person=" + person.toString() +
                ", arr=" + Arrays.toString(arr) +
                ", myList=" + myList +
                ", myMap=" + myMap +
                ", mySet=" + mySet +
                ", wife='" + wife + '\'' +
                ", myPro=" + myPro +
                '}';
    }

    //getting、setting
}

配置文件(applicationContext.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="person" class="com.kang.pojo.Person">
        <property name="name" value="zhangsan"/>
        <property name="age" value="12"/>
    </bean>

    <bean id="student" class="com.kang.pojo.Student">
        <!--普通值注入,value:具体属性值-->
        <property name="name" value="jerry"/>

        <!--Bean注入,ref:对象-->
        <property name="person" ref="person"/>

        <!--数组注入-->
        <property name="arr">
            <array>
                <value>AAA</value>
                <value>BBB</value>
                <value>CCC</value>
            </array>
        </property>

        <!--List注入-->
        <property name="myList">
            <list>
                <value>111</value>
                <value>222</value>
                <value>333</value>
            </list>
        </property>

        <!--Map注入-->
        <property name="myMap">
            <map>
                <entry key="aaa" value="aaaa"></entry>
                <entry key="bbb" value="bbbb"></entry>
                <entry key="ccc" value="cccc"></entry>
            </map>
        </property>

        <!--Set注入-->
        <property name="mySet">
            <set>
                <value>111</value>
                <value>222</value>
                <value>333</value>
            </set>
        </property>

        <!--null注入-->
        <property name="wife">
            <null/>
        </property>

        <!--Properties注入-->
        <property name="myPro">
            <props>
                <prop key="aaa">aaaa</prop>
                <prop key="bbb">bbbb</prop>
                <prop key="ccc">cccc</prop>
            </props>
        </property>
    </bean>
</beans>

测试类:

public class myTest {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student) context.getBean("student");
        System.out.println(student.toString());
    }
    /*
    Student{
        name='jerry',
        person=Person{
            name='zhangsan',
             age=12
        },
        arr=[AAA, BBB, CCC],
        myList=[111, 222, 333],
        myMap={
            aaa=aaaa,
            bbb=bbbb,
            ccc=cccc
        },
        mySet=[111, 222, 333],
        wife='null',
        myPro={
           bbb=bbbb,
           aaa=aaaa,
           ccc=cccc
        }
    }
     */
}

4)p、c命名空间注入

实体类

public class User {
    private String name;
    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }

    //getting、setting
}

配置文件

<?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:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--p命名空间注入,可以直接注入属性的值:properties-->
    <bean id="user" class="com.kang.pojo.User" p:name="jarry" p:age="15"/>

    <!--c命名空间注入,通过构造器注入:construct-args-->
    <bean id="user2" class="com.kang.pojo.User" c:name="张三" c:age="18"/>
</beans>

测试类

@Test
public void test1(){
  ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
  User user = context.getBean("user", User.class);
  System.out.println(user);

  User user2 = context.getBean("user2", User.class);
  System.out.println(user2);
}

注意:p命名和c命名空间不能直接使用,需要导入xml约束。

xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"

5)Bean作用域(scope属性)

1.单例模式(Spring默认的机制)

<bean id="accountService" class="com.something.DefaultAccountService" scope="singleton"/>

2.原型模式(多例模式)

每次从容器中get的时候,都会产生一个新的对象。

<bean id="accountService" class="com.something.DefaultAccountService" scope="prototype"/>

3.其余的request、session、application,这些个只能在web开发中使用到。

4.Bean的自动装配

  • 自动装配是spring满足bean依赖一种方式。
  • Spring会在上下文中自动寻找,并自动给bean装配属性。

在Spring中有三种装配的方式:

  1. 在xmI中显示的配置
  2. 在java中显示配置
  3. 隐式的自动装配bean 【重要】

1)搭建环境

    public class Cat {
        public void shout(){
            System.out.println("喵喵");
        }
    }
    
    public class Dog {
        public void shout(){
            System.out.println("旺旺");
        }
    }
    
    public class Person {
    
        private Cat cat;
        private Dog dog;
        private String name;
    
        @Override
        public String toString() {
            return "Person{" +
                    "cat=" + cat +
                    ", dog=" + dog +
                    ", name='" + name + '\'' +
                    '}';
        }
    	//getting、setting
    }

2)ByName自动装配

    <bean id="cat" class="com.kuang.pojo.Cat"/>
    <bean id="dog" class="com.kuang.pojo.Dog"/>
    
    <!--byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanId-->
    <bean id="person" class="com.kuang.pojo.Person" autowire="byName">
      <property name="name" value="小海子"/>
    </bean>

3)ByType自动装配

    <bean class="com.kuang.pojo.Cat"/>
    <bean class="com.kuang.pojo.Dog"/>
    
    <!--byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanId
        byType:会自动在容器上下文中查找,和自己对象属性类型相同的bean。
    -->
    <bean id="person" class="com.kuang.pojo.Person" autowire="byType">
      <property name="name" value="小海子"/>
    </bean>

小结:

  • byname的时候,需要保证所有bean的id唯一 ,并且这个bean需要和自动注入的属性的set方法的值一致。
  • bytype的时候, 需要保证所有bean的class唯一 ,并且这个bean需要和自动注入的属性的类型一致;全局唯一,id属性可以省略。

4)使用注解实现自动装配

jdk1.5支持的注解,Spring2.5支持注解

他们的作用就和在xml配置文件中的bean标签中写一个标签的作用是一样的。

要使用注解须知:

  1. 导入约束
  2. 配置注解的支持
    <?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
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd">
    
        <context:annotation-config/>
    
    </beans>
@Autowired

作用:自动按照类型注入。只要容器中唯一的一个bean对象类型和要注入的变量类型匹配,就可以注入成功。

如果ioc容器中没任何bean的类型和要注入的变量类型匹配,则报错。

如果Ioc容器中多个类型匹配时:

出现位置:可以是变量上,也可以是方法上。

细节:在使用注解注入时,set方法就不是必须的了。

    public @interface Autowired {
        boolean required() default true;
    }

科普:

    @Nullable  //字段标记了这个注解,说明这个字段可以为null。

测试

    public class Person {
        //如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
        @Autowired(required = false)
        private Cat cat;
        @Autowired//自动装配通过类型。名字
        private Dog dog;
        private String name;
    }

如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解【@Autowired】完成的时候我们可以使用@Qualifier(value=“xx”)去配合@Autowired的使用,指定一个唯一的bean对象注入。

    public class Person {
        @Autowired
        @Qualifier(value = "cat22")
        private Cat cat;
    
        @Autowired
        @Qualifier(value = "dog11")
        private Dog dog;
        private String name;
    }
    
    <bean id="cat22" class="com.kuang.pojo.Cat"/>
    <bean id="dog22" class="com.kuang.pojo.Dog"/>
    <bean id="cat11" class="com.kuang.pojo.Cat"/>
    <bean id="dog11" class="com.kuang.pojo.Dog"/>
    <bean id="person" class="com.kuang.pojo.Person"/>
@Qualifier

作用:在照类中注入的基础之上再照名称注入。在给类成员注入时不能单独使用。但是在给方法参数注入时可以。

属性:value:用于指定注入bean的id。

@Resource

作用:直接照bean的id注入。它可以独立使用。

属性:name:用于指定bean的id。

    public class Person {
        @Resource(name = "cat22")
        private Cat cat;
    
        @Resource//自动装配通过名字。类型
        private Dog dog;
        private String name;
    }
    
    <bean id="cat" class="com.kuang.pojo.Cat"/>
    <bean id="cat22" class="com.kuang.pojo.Cat"/>
    <bean id="dog" class="com.kuang.pojo.Dog"/>
    <bean id="person" class="com.kuang.pojo.Person"/>

注意:以上注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。
另外,集合类型的注入只能通过XML来实现。

小结:

@Resource和@Autowired的区别:

  • 都是用来自动装配的,都可以放在属性字段上。
  • @ Autowired 通过byType的方式实现,而且必须要求这个对象存在。
  • @Resource 默认通过byname的方式实现,如果找不到名字,则通过byType实现。如果两个都找不到的情况下,就报错。
  • @ Autowired 通过byType的方式实现,@Resource 默认通过byname的方式实现

5.使用注解开发

在Spring4之后,要使用注解开发,必须要保证aop的包导入了。

使用注解需要导入context约束,

    <?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
            https://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context
            https://www.springframework.org/schema/context/spring-context.xsd">
    
        <!--指定要扫描的包,这个包下的注解就会生效-->
        <context:component-scan base-package="com.kuang.pojo"/>
        <context:annotation-config/>
    
    </beans>

1)属性如何注入

@Value

作用:用于注入基本类型和String类型的数据。

属性:value:用于指定数据的值。它可以使用spring中SpEL(也就是spring的el表达式)

SpEL的写法:${表达式}

    public class User {
    
        //相当于 <property name="name" value="zhangsan">
        @Value("zhangsan")
        private String name;
    
        public String getName() {
            return name;
        }
    
    }

2)用于创建对象的注解

他们的作用就和在XML配置文件中编写一个标签实现的功能是一样的。

  • @Component

作用:用于把当前类对象存入spring容器中。

属性: value:用于指定bean的id。当我们不写时,它的默认值是当前类名,且首字母改小写。

    等价于<bean id="user" class="com.kuang.pojo.User"/>
  • Controller:一般用在表现层【@Controller】
  • Service:一般用在业务层【@Service】
  • Repository:一般用在持久层【@Repository】

以上三个注解他们的作用和属性与Component是一模一样。

他们是spring框架为我们提供明确的层使用的注解,使我们的层对象更加清晰。

3)用于作用域的注解

@Scope

他们的作用就和在bean标签中使用scope属性实现的功能是一样的。

作用:用于指定bean的作用范围。

属性:value:指定范围的取值。常用取值:singleton,prototype

    @Scope("prototype")
    public class User {
        private String name;
    
        public String getName() {
            return name;
        }
    }

小结:

xml和注解:

  • xml 更加万能,适用于任何场合,维护简单方便。
  • 注解 不是自己类使用不了,维护相对复杂。

xml与注解最佳实践:

  • xml用来管理bean;
  • 注解只负责完成属性的注入;
  • 我们在使用的过程中,只需要注意一个问题:必须让注解生效,就要开启注解的支持。

6.自定义配置类的注解

该类是一个配置类,它的作用和bean.xml是一样的。

@Configuration

作用:指定当前类是一个配置类。

细节:当配置类作为AnnotationConfigApplicationContext对象创建的参数时,该注解可以不写。

@ComponentScan

作用:用于通过注解指定spring在创建容器时要扫描的包。

属性:value:它和basePackages的作用是一样的,都是用于指定创建容器时要扫描的包。

我们使用此注解就等同于在xml中配置了:

<!--告知spring在创建容器时要扫描的包,配置所需要的标签不是在beans的约束中,而是一个名称为context名称空间和约束中-->
<context:component-scan base-package="com.itheima"></context:component-scan>
@Bean

作用:用于把当前方法的返回值作为bean对象存入spring的ioc容器中。

属性:name:用于指定bean的id。当不写时,默认值是当前方法的名称。

细节:当我们使用注解配置方法时,如果有方法参数,spring框架会去容器中查找可用的bean对象。查找的方式和Autowired注解的作用是一样的。

@Import

作用:用于导入其他的配置类。

属性:value:用于指定其他配置类的字节码。

当我们使用Import的注解之后,Import注解的类就父配置类,而导入的都是子配置类。

@PropertySource

作用:用于指定properties文件的位置。

属性:value:指定文件的名称和路径。

关键字:classpath,表示类路径下。

7.使用Java的方式配置Spring

我们现在完全不适用Spring的xml配置了,全权交给Java来做。

JavaConfig是Spring的一个子项目,在Spring4后,成为一个核心功能。

代码实现:

User实体类

    //这个注解的意思,就是说明这个类被Spring接管了,注册到容器中
    @Component
    public class User {
    
        private String name;
    
        public String getName() {
            return name;
        }
    
        @Value("zhangsan")//属性注入值
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "User{" +
                    "name='" + name + '\'' +
                    '}';
        }
    }

配置文件

    @Configuration
    @ComponentScan("com.kuang.pojo")
    @Import(myConfig2.class)
    public class myConfig {
    
        //注册一个bean,就相当于我们之前写的一个Bean标签
        //这个方法的名字,就相当于bean标签中的id属性
        //这个方法的返回值,就相当于bean标签中的class属性
        @Bean
        public User user(){
            return new User();//就是返回要注入到bean的对象
        }
    
    }

测试类

    public class myTest {
        public static void main(String[] args) {
            //如果完全是用来配置类方式去做,我们只能通过Annotation 上下文来获取容器,通过配置类的class对象加载。
            ApplicationContext context = new AnnotationConfigApplicationContext(myConfig.class);
            User name = (User) context.getBean("user");
            System.out.println(name.getName());
        }
    }

8.生命周期相关(了解)

他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的。

  • PreDestroy

作用:用于指定销毁方法。

  • PostConstruct

作用:用于指定初始化方法。

9.spring整合junit4

1)Junit

1、应用程序的入口:main方法

2、junit单元测试中,没有main方法也能执行

junit集成了一个main方法,该方法就会判断当前测试类中哪些方法有 @Test注解,如果有junit注解就让方法执行。如果没有则不能执行。

3、junit不会管我们是否采用spring框架

在执行测试方法时,junit根本不知道我们是不是使用了spring框架,所以也就不会为我们读取配置文件/配置类创建spring核心容器。

4、由以上三点可知

当测试方法执行时,没有Ioc容器,就算写了Autowired注解,也无法实现注入。

2)使用Junit单元测试

Spring整合junit的配置:

1、导入spring整合junit的jar(坐标)

2、使用Junit提供的一个注解把原有的main方法替换了,替换成spring提供的

@Runwith(SpringJUnit4ClassRunner.class)

3、告知spring的运行器,spring和ioc创建是基于xml还是注解的,并且说明位置

@ContextConfiguration

参数说明:

  • locations:指定xml文件的位置,加上classpath关键字,表示在类路径下。
  • classes:指定注解类所在地位置。

注意:当我们使用spring 5.x版本的时候,要求junit的jar必须是4.12及以上。

二、使用IOC实现账户的CRUD

1 基于xml形式

1)引用外部属性文件

2)SPEL表达式

1.简介
Spring Expression Language,Spring表达式语言,简称SpEL。支持运行时查询并可以操作对象图。
和JSP页面上的EL表达式、Struts2中用到的OGNL表达式一样,SpEL根据JavaBean风格的getXxx()、setXxx()方法定义的属性访问对象图,完全符合我们熟悉的操作习惯。

2.基本语法
SpEL使用#{…}作为定界符,所有在大框号中的字符都将被认为是SpEL表达式。

3.使用字面量
	●整数:<property name="count" value="#{5}"/>
	●小数:<property name="frequency" value="#{89.7}"/>
	●科学计数法:<property name="capacity" value="#{1e4}"/>
	●String类型的字面量可以使用单引号或者双引号作为字符串的定界符号
		<property name=”name” value="#{'Chuck'}"/>
		<property name='name' value='#{"Chuck"}'/>
	●Boolean:<property name="enabled" value="#{false}"/>

4.引用其他bean
    <bean id="emp04" class="com.atguigu.parent.bean.Employee">
        <property name="empId" value="1003"/>
        <property name="empName" value="jerry"/>
        <property name="age" value="21"/>
        <property name="detp" value="#{dept}"/>
    </bean>

5.引用其他bean的属性值作为自己某个属性的值
    <bean id="emp05" class="com.atguigu.parent.bean.Employee">
        <property name="empId" value="1003"/>
        <property name="empName" value="jerry"/>
        <property name="age" value="21"/>
        <property name="deptName" value="#{dept.deptName}"/>
    </bean>

6.调用非静态方法
    <!-- 创建一个对象,在SpEL表达式中调用这个对象的方法 -->
    <bean id="salaryGenerator" class="com.atguigu.spel.bean.SalaryGenerator"/>

    <bean id="employee" class="com.atguigu.spel.bean.Employee">
        <!-- 通过对象方法的返回值为属性赋值 -->
        <property name="salayOfYear" value="#{salaryGenerator.getSalaryOfYear(5000)}"/>
    </bean>

7.调用静态方法
    <bean id="employee" class="com.atguigu.spel.bean.Employee">
        <!-- 在SpEL表达式中调用类的静态方法 -->
        <property name="circle" value="#{T(java.lang.Math).PI*20}"/>
    </bean>

8.运算符
    ①算术运算符:+、-、*、/、%、^
    ②字符串连接:+
    ③比较运算符:<>、==、<=、>=、lt、gt、eq、le、ge
    ④逻辑运算符:and, or, not, |
    ⑤三目运算符:判断条件?判断结果为true时的取值:判断结果为false时的取值
    ⑥正则表达式:matches
代码如下:

配置文件

<?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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.2.xsd
		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-4.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
  
	<bean id="accountDao" class="com.atguigu.dao.impl.AccountDaoImpl">
		<property name="runner" ref="runner"></property>
	</bean>
	<bean id="accountService" class="com.atguigu.service.impl.AccountServiceImpl">
		<property name="accountDao" ref="accountDao"></property>
	</bean>
	<bean id="account" class="com.atguigu.domain.Account"></bean>
  
	<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
		<constructor-arg name="ds" ref="dataSource"></constructor-arg>
	</bean>
  
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
		<property name="username" value="root"></property>
		<property name="password" value="123456"></property>
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
	</bean>
</beans>

持久层

/*
  账户的持久层实现类
 */
public class AccountDaoImpl implements IAccountDao {
    
    private QueryRunner runner;

    public void setRunner(QueryRunner runner) {
        this.runner = runner;
    }

    public List<Account> findAllAccount() {
        try{
            return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public Account findAccountById(Integer accountId) {
        try{
            return runner.query("select * from account where id = ? ",new BeanHandler<Account>(Account.class),accountId);
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void saveAccount(Account account) {
        try{
            runner.update("insert into account(name,money)values(?,?)",account.getName(),account.getMoney());
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void updateAccount(Account account) {
        try{
            runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void deleteAccount(Integer accountId) {
        try{
            runner.update("delete from account where id=?",accountId);
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

业务层

/*
  账户的业务层实现类
 */
public class AccountServiceImpl implements IAccountService{
    
    private IAccountDao accountDao;

    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public List<Account> findAllAccount() {
        return accountDao.findAllAccount();
    }

    public Account findAccountById(Integer accountId) {
        return accountDao.findAccountById(accountId);
    }

    public void saveAccount(Account account) {
        accountDao.saveAccount(account);
    }

    public void updateAccount(Account account) {
        accountDao.updateAccount(account);
    }

    public void deleteAccount(Integer acccountId) {
        accountDao.deleteAccount(acccountId);
    }
}

测试类

public class Test1 {
    ApplicationContext ioc=new ClassPathXmlApplicationContext("applicationContext.xml");
    @Test
    public void test1(){
        IAccountService service= (IAccountService) ioc.getBean("accountService");
        service.deleteAccount(2);
    }
}

2. 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:aop="http://www.springframework.org/schema/aop"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:jdbc="http://www.springframework.org/schema/jdbc"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xsi:schemaLocation="http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.2.xsd
		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-4.2.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd
		http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd">
  
	<!--设置自动扫描的包-->
	<context:component-scan base-package="com.atguigu"></context:component-scan>
  
	<bean id="runner" class="org.apache.commons.dbutils.QueryRunner" scope="prototype">
		<constructor-arg name="ds" ref="dataSource"></constructor-arg>
	</bean>
  
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="url" value="jdbc:mysql://localhost:3306/eesy"></property>
		<property name="username" value="root"></property>
		<property name="password" value="123456"></property>
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
	</bean>
</beans>

持久层

/**
 * 账户的持久层实现类
 */
@Repository(value = "accountDao")
public class AccountDaoImpl implements IAccountDao {
    @Autowired
    private QueryRunner runner;

    public List<Account> findAllAccount() {
        try{
            return runner.query("select * from account",new BeanListHandler<Account>(Account.class));
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public Account findAccountById(Integer accountId) {
        try{
            return runner.query("select * from account where id = ? ",new BeanHandler<Account>(Account.class),accountId);
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void saveAccount(Account account) {
        try{
            runner.update("insert into account(name,money)values(?,?)",account.getName(),account.getMoney());
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void updateAccount(Account account) {
        try{
            runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    public void deleteAccount(Integer accountId) {
        try{
            runner.update("delete from account where id=?",accountId);
        }catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

业务层

/**
 * 账户的业务层实现类
 */
@Service("accountService")
public class AccountServiceImpl implements IAccountService{
    @Autowired
    private IAccountDao accountDao;

    public List<Account> findAllAccount() {
        return accountDao.findAllAccount();
    }

    public Account findAccountById(Integer accountId) {
        return accountDao.findAccountById(accountId);
    }

    public void saveAccount(Account account) {
        accountDao.saveAccount(account);
    }

    public void updateAccount(Account account) {
        accountDao.updateAccount(account);
    }

    public void deleteAccount(Integer acccountId) {
        accountDao.deleteAccount(acccountId);
    }
}

测试类

public class AccountServiceTest {
    @Test
    public void testFindAll() {
        //1.获取容易
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        List<Account> accounts = as.findAllAccount();
        for(Account account : accounts){
            System.out.println(account);
        }
    }

    @Test
    public void testFindOne() {
        //1.获取容易
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        Account account = as.findAccountById(1);
        System.out.println(account);
    }

    @Test
    public void testSave() {
        Account account = new Account();
        account.setName("test");
        account.setMoney(12345f);
        //1.获取容易
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        as.saveAccount(account);
    }

    @Test
    public void testUpdate() {
        //1.获取容易
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        Account account = as.findAccountById(4);
        account.setMoney(23456f);
        as.updateAccount(account);
    }

    @Test
    public void testDelete() {
        //1.获取容易
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        //2.得到业务层对象
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        //3.执行方法
        as.deleteAccount(4);
    }
}

3. 纯注解配置

代码如下:

配置类

/**
 * @author Guohai
 * @createTime 2020-07-13 17:14
 */
@Configuration
@ComponentScan("com.atguigu")
@Import(JdbcConfig.class)
@PropertySource("classpath:c3p0.properties")
public class SpringConfig {

}

配置子类

/**
 * @author Guohai
 * @createTime 2020-07-13 17:16
 */
public class JdbcConfig {
    @Bean(name="runner")
    @Scope(value = "prototype")
    public QueryRunner getRunner(@Qualifier("ds1") DataSource dataSource) {
        QueryRunner runner = new QueryRunner(dataSource);
        return runner;
    }

    private static DataSource dataSource = null;

    @Bean(name="ds1")
    public DataSource getDataSource() {
        try {
            Properties prop = new Properties();
            InputStream is = JdbcConfig.class.getClassLoader().getResourceAsStream("jdbc.properties");
            prop.load(is);
            dataSource = DruidDataSourceFactory.createDataSource(prop);
            return dataSource;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
  
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    @Bean(name="ds2")
    public DataSource getDataSource2(){
        try {
            ComboPooledDataSource dataSource=new ComboPooledDataSource();
            dataSource.setDriverClass(driver);
            dataSource.setJdbcUrl(url);
            dataSource.setUser(username);
            dataSource.setPassword(password);
            return dataSource;
        } catch (PropertyVetoException e) {
            e.printStackTrace();
        }
        return null;
    }
}

测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountServiceTest {

    @Autowired
    private IAccountService as = null;

    @Test
    public void testFindAll() {
        //3.执行方法
        List<Account> accounts = as.findAllAccount();
        for(Account account : accounts){
            System.out.println(account);
        }
    }

    @Test
    public void testFindOne() {
        //3.执行方法
        Account account = as.findAccountById(1);
        System.out.println(account);
    }

    @Test
    public void testSave() {
        Account account = new Account();
        account.setName("test anno");
        account.setMoney(12345f);
        //3.执行方法
        as.saveAccount(account);
    }

    @Test
    public void testUpdate() {
        //3.执行方法
        Account account = as.findAccountById(4);
        account.setMoney(23456f);
        as.updateAccount(account);
    }

    @Test
    public void testDelete() {
        //3.执行方法
        as.deleteAccount(4);
    }
}

链接: 对Spring深入的理解 | 概念的总结
链接: Spring IOC详解
链接: Spring AOP详解
链接: Spring 事务详解


如果有收获!!! 希望老铁们来个三连,点赞、收藏、转发
创作不易,别忘点个赞,可以让更多的人看到这篇文章,顺便鼓励我写出更好的博客
  • 46
    点赞
  • 169
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值