Spring 依赖注入详解

    技术2022-08-01  71

    一、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中有三种装配的方式:

    在xmI中显示的配置在java中显示配置隐式的自动装配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标签中写一个标签的作用是一样的。

    要使用注解须知:

    导入约束配置注解的支持 <?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 事务详解


    如果有收获!!! 希望老铁们来个三连,点赞、收藏、转发 创作不易,别忘点个赞,可以让更多的人看到这篇文章,顺便鼓励我写出更好的博客
    Processed: 0.014, SQL: 9