精华内容
下载资源
问答
  • 对spring依赖注入的实现解释
    千次阅读
    2018-09-27 15:49:24

    依赖注入是spring的一个特性,从配置层面解决了程序耦合、依赖问题,spring提供了构造函数依赖注入、Setter方法依赖注入、自动装配依赖注入和@autowired注解依赖注入等多种实现方式。

    那么依赖注入是如何实现的?第一反应就是java反射呗,比如构造函数注入,我们可以通过反射读取Bean类的构造函数,参数个数,参数类型,所以只要我们在xml配置文件中指定了参数类型或参数顺序就可以轻松通过反射创建出该Bean的实例。但是实践过程中我们发现,xml配置文件中指定name=参数名称也可以实现依赖注入,这是java反射很难实现的至少jdk1.8以下实现不了,因为jdk1.8以下通过反射得不到具体的参数名称。看一个案例。

    Student.java

    package com.marcus.spring.beans;
    
    public class Student {
    	private Integer age;
    	private String name;
    	private String gender;
    	
    	public Student() {
    	}
    	public Student(String name, String gender, Integer age) {
    		this.name = name;
    		this.age = age;
    		this.gender = gender;
    	}
    	public void setAge(Integer age) {
    		this.age = age;
    	}
    	public Integer getAge() {
    		return age;
    	}
    	public void setName(String name) {
    		this.name = name;
    	}
    	public String getName() {
    		return name;
    	}
    	public String getGender() {
    		return gender;
    	}
    	public String toString() {
    		return String.format("{name: %s, gender: %s, age: %d}", this.name, this.gender, this.age);
    	}
    }
    

    xml配置文件 ioc-di-asm.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-3.0.xsd">
       
       <!-- Definition for student bean -->
       <bean id="student1" class="com.marcus.spring.beans.Student">
       	<constructor-arg  value="student1" />
       	<constructor-arg  value="male" />
       	<constructor-arg  value="11" />
       </bean>   
       <bean id="student2" class="com.marcus.spring.beans.Student">
       	<constructor-arg  type="java.lang.Integer" value="22" />
       	<constructor-arg  value="student2" />
       	<constructor-arg  value="male" />
       </bean>
       <bean id="student3" class="com.marcus.spring.beans.Student">
       	<constructor-arg  type="java.lang.Integer" value="33" />
       	<constructor-arg  name="gender" value="female" />
       	<constructor-arg  value="student3" />	
       </bean>
    </beans>
    

    测试类 DIAsmApp.java

    public class DIAsmApp {
    	public static void main(String[] args) {
    		AbstractApplicationContext context = new ClassPathXmlApplicationContext("ioc-di-asm.xml");
    		
    		Student student1 = context.getBean("student1", Student.class);
    		System.out.println("student1: " + student1.toString());
    
    		Student student2 = context.getBean("student2", Student.class);
    		System.out.println("student2: " + student2.toString());
    		
    		Student student3 = context.getBean("student3", Student.class);
    		System.out.println("student3: " + student3.toString());	
    		
    		context.close();
    	}
    }
    

    输出结果

    student1: {name: student1, gender: male, age: 11}
    student2: {name: student2, gender: male, age: 22}
    student3: {name: student3, gender: female, age: 33}
    

    案例说明

    1、student1,可以用反射实现

    xml配置了3个constructor-arg,没有type、index、name等其它装饰,这种情况我们通过java反射可以成功创建实例,即找3个参数的构造函数,Student(String name, String gender, Integer age),然后按照constructor-arg出现顺序依次给构造函数参数赋值,并创建实例。

    2、student2,可以用反射实现

    xml配置了3个constructor-arg:
    <constructor-arg type=“java.lang.Integer” value=“22” />
    <constructor-arg value=“student2” />
    <constructor-arg value=“male” />
    第1个参数标记为Integer类型,其余2个只有value值,没其它标识,这种情况我们依然可以通过java反射成功创建实例。

    • 找到3个参数的构造函数,Student(String name, String gender, Integer age);
    • 读取第1个constructor-arg type=“java.lang.Integer”,构造函数中找到类型为Integer的参数,发现是第3个参数,则设置arg2 = 22
    • 读取第2个constructor-arg,构造函数为arg0,arg1未设置,先后顺序赋值,arg0 = student2
    • 读取第3个constructor-arg,arg1未设置,arg1 = male
    3、student3,java反射无法实现

    xml配置了3个constructor-arg:
    <constructor-arg type=“java.lang.Integer” value=“33” />
    <constructor-arg name=“gender” value=“female” />
    <constructor-arg value=“student3” />
    第1个参数标记为Integer类型,第2个参数设置了name,第3个参数没特殊标识,假设可以通过java反射实现,则实现步骤应该是:

    • 找到3个参数的构造函数,Student(String name, String gender, Integer age);
    • 读取第1个constructor-arg type=“java.lang.Integer”,构造函数中找到类型为Integer的参数,发现是第3个参数,则设置arg2 = 22
    • 读取第2个constructor-arg,构造函数为arg0,arg1未设置,先后顺序赋值,arg0 = female
    • 读取第3个constructor-arg,arg1未设置,arg1 = student3

    我们得到student bean为{name=female, gender=student3,age=33},姓名变成了性别,性别变成了姓名,不是我们想要的结果,java反射失败!

    那么spring依赖注入为何可以正常工作呢?原因是spring使用了asm框架,可以读取java类字节码,读取到构造函数的参数名称,如上文的student3配置,spring可以读取到第二个constructor-arg name="gender"对应构造函数的arg1,所以就可以正常工作了。
    ASM框架代码演示:

    AsmDemo.java

    package com.marcus.spring.aop;
    
    import java.lang.reflect.Constructor;
    
    import org.springframework.core.LocalVariableTableParameterNameDiscoverer;
    
    import com.marcus.spring.beans.Student;
    
    public class AsmDemo {
    	public static void main(String[] args) throws ClassNotFoundException {
    		LocalVariableTableParameterNameDiscoverer localVariableTableParameterNameDiscoverer 
    			= new LocalVariableTableParameterNameDiscoverer();
    		Class<?> forName = Class.forName(Student.class.getName());
    		Constructor<?>[] constructors = forName.getConstructors();
    		for (Constructor<?> constructor : constructors) {
    			String argNames = "";
    			String[] parameterNames = localVariableTableParameterNameDiscoverer
    					.getParameterNames(constructor);
    			for (String parameterName : parameterNames) {
    				argNames += argNames.length() < 1 ? parameterName : "," + parameterName;
    			}
    			System.out.println(argNames.length()<1 ? constructor.getName() + "()" 
    					: constructor.getName() + "(" + argNames + ")");
    		}
    		//output:		
    		//com.marcus.spring.beans.Student()
    		//com.marcus.spring.beans.Student(name,gender,age)
    	}
    }
    

    通过ASM框架,我们读取到了com.marcus.spring.beans.Student(name,gender,age)构造函数参数名称,继续student3 bean注入的实现步骤:

    student3在xml文件中,配置了3个constructor-arg:
    <constructor-arg type=“java.lang.Integer” value=“33” />
    <constructor-arg name=“gender” value=“female” />
    <constructor-arg value=“student3” />
    第1个参数标记为Integer类型,第2个参数设置了name,第3个参数没特殊标识,通过java反射+ASM框架,实现步骤应该是:

    • 找到3个参数的构造函数,Student(String name, String gender, Integer age);
    • 读取第1个constructor-arg type=“java.lang.Integer”,构造函数中找到类型为Integer的参数,发现是第3个参数,则设置arg2 = 22
    • 读取第2个constructor-arg name=“gender”,构造函数中找到名称为gender的参数,发现是第2个参数,则设置arg1=female
    • 读取第三个constructor-arg,arg0未设置,arg0 = student3

    我们得到student bean为{name=student3, gender=female,age=33},成功!

    小结

    spring框架广泛使用了ASM框架,我们可以从spring的jar包构成可以看出ASM对于spring的重要性。以3.2.5.RELEASE版本为例,ASM部分在spring-core-3.2.5.RELEASE.jar包,spring最核心的jar包中!AOP,cglib等都需要ASM读取、操作java类。

    更多相关内容
  • spring依赖注入

    千次阅读 2022-05-28 19:38:52
    在maven项目中的pom.xml文件中配置spring依赖: <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.6....

    目录

    1、使用bean标签注入

    1、pom.xml文件配置

    2、spring配置文件(存放bean、spring注解等相关信息的文件)

    3、bean标签生成对象

    4、对象的依赖注入

    (1)、通过set方法:

    (2)通过构造方法注入(有参构造)。

    5、普通数据类型、集合的依赖注入

    2、原始注解

     1、@Repository

    2、@Service("userService")

    3、注入对象属性

    3、@Autowired+@Qualifier=@Resource

    3.1@Resource

    3.2@Autowired

    3.3@Qualifier

    4、注入普通属性

    5、新注解

     5.1@Configuration、@ComponentScan、@Import

    5.2@PropertySource、@Bean


    1、使用bean标签注入

    1、pom.xml文件配置

    在maven项目中的pom.xml文件中配置spring依赖:

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.6.RELEASE</version>
        </dependency>

    2、spring配置文件(存放bean、spring注解等相关信息的文件)

    创建spring的配置文件(pom.xml配置了spring以来后可以直接生成spring的配置文件)applicationContext.xml。

    3、编写对应的接口(userDao、userService)和实现类(DaoImpl、ServiceImpl)。在实现类中复写接口的方法。

    3、bean标签生成对象

    在spring的配置文件applicationContext.xml中创建bean标签,让spring来生成对象:

    <bean id="userDao" class="com.gdut.depen.Dao.Impl.DaoImpl">

    这里的Id属性是bean标签的唯一属性不可重复,对应了一个具体的对象,例如在程序中连续使用两次getBeam("userDao"),返回的是一样的地址。class属性是对应实现类的全类名,这里用了反射机制在spring中生成DaoImpl对象。

    4、对象的依赖注入

    为什么要依赖注入。在使用spring的依赖注入之前,虽然已经有各种各样的对象存在于spring容器中,但是如果一个对象要调用另一个对象的方法还需要再Java代码中创建一个applicationcontext对象并使用getbean()来获得另一个类,如果可以再spring容器中就可以让一个类获得了另一个类的对象就会方便很多

    将userDao注入userService有两个方法:构造方法、set方法。这样子就可以在spring中直接将userDao对象注入到userService对象中,不需要在ServiceImpl中通过以下代码来获取userDao对象

    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    userDao userDao = app.getBean("userDao");
    userDao.save();

    (1)、通过set方法:

    在类中建一个成员属性,并为其创建set方法:

        private UserDao userDao;
    
        public void setUserDao(UserDao userDao) {
                    this.userDao = userDao  
            }

    接着在xml配置文件中的serviceDao对应的bean标签里面注入userDao对象

        <bean id="serviceDao" class="com.gdut.depen.Service.Impl.serviceImpl">
            <property name="userDao" ref="userDao"></property>
        </bean>

    在<property>标签里面,name属性指向的是ServiceImpl类里面的构造方法里面setUserDao里面的UserDao,其中set方法后面跟的属性名第一个字母必须大写,不然spring配置文件中识别不出这是对属性的set方法,可以理解为配置文件中是根据name的值去找符合规则且能对应上的set方法。而在配置文件中name=userDao的u可以小写也可以大写。而ref属性的userDao代表的是spring容器中已经有了的userDao对象,所以这里的值应该跟userDao的bean标签里面的Id属性一致。

    注:为了使 JavaBean 的属性名和存取方法都符合规范, Sun 在 JSR 文档中规定了属性名和存取方法名的映射规则: ① 属性名对应的存取方法为 ge t/set 加上首字母大写的属性名,如属性 userName 的存取方法为 setUserName/getUserName 。这样属性名和存取方法都符合命名规范。这个规则强制的,如果不符合规则就会出现异常,在xml配置文件中

     这里p:后面跟着userDao-ref,ref="userDao",意思是注入的不是一个基础变量,是一个引用变量,引用的指向是userDao的id值

    (2)通过构造方法注入(有参构造)。

    先在ServiceImpl设置一个有参的构造方法

        public UserServiceImpl(UserDao userDao) {
            this.userDao = userDao;
        }
    
        public UserServiceImpl() {
        }

    然后在配置文件中编写bean标签

        <bean id="userService2" class="com.itheima.service.impl.UserServiceImpl">
            <constructor-arg name="userDao" ref="userDao"></constructor-arg>
        </bean>

    其中<constructor-arg>指的是构造方法,name属性后面跟着的指的是ServiceImpl有参构造方法中的属性名,而ref指向的是spring容器中的对象,即userDao的bean标签的id属性值。

    5、普通数据类型、集合的依赖注入

    假设,在userDaoImpl实现类中创建了以下的属性:

        private String username;
        private int age;    
        private List<String> strList;
        private Map<String, User> userMap;
        private Properties properties;

    可以在bean标签内为这些属性注入值:

        <bean id="userDao" class="com.itheima.dao.impl.UserDaoImpl">
            <property name="username" value="zhangsan"/>
            <property name="age" value="18"/>
            <property name="strList">
                <list>
                    <value>aaa</value>
                    <value>bbb</value>
                    <value>ccc</value>
                </list>
            </property>
            <property name="userMap">
                <map>
                    <entry key="u1" value-ref="user1"></entry>
                    <entry key="u2" value-ref="user2"></entry>
                </map>
            </property>
            <property name="properties">
                <props>
                    <prop key="p1">ppp1</prop>
                    <prop key="p2">ppp2</prop>
                    <prop key="p3">ppp3</prop>
                </props>
            </property>
        </bean>

    可以看到,对于普通数据类型、集合的注入,采用的是类似于对象set方法注入的<property>标签,里面没有ref属性,因为ref属性是针对对象的,而是根据具体属性的类型采用不同的标签。

    2、原始注解

    需要在配置文件中配置注解搜寻器,告诉spring去哪里找注解

    <context:component-scan base-package="com.gdut"></context:component-scan>
    

     1、@Repository

    //<bean id="userDao" class="com.gdut.depen.Dao.Impl.DaoImpl">
    @Repository("userDao")

    采用@Repository注解可以带起在配置文件中的<bean>,因为这个注解是在类的上面,所以就可以直接找到这个类而不需要<bean>里面的class值;注解里面的值等价于<bean>里面的id属性。

    2、@Service("userService")

    道理等同@Repository。

    3、注入对象属性

    对于注解注入对象,需要用到以下注解来完成把spring中已经有的对象注入给目标属性

    例如在serviceImpl中需要userDao对象,serviceImpl类中创建了一个userDao变量

    private userDao userDao;

    3、@Autowired+@Qualifier=@Resource

        @Autowired
        @Qualifier("userDao")
        private useDao userDao;

    这样就相当于把spring容器中id为userDao的对象赋给该类的属性userDao,相当于<property name="userDao" ref="userDao"></property>

    当使用这些注解的时候,set方法可以不写。把注解放在属性上,就直接通过反射赋值给了属性。

    3.1@Resource

    如果使用@Ressource,就等同于同时使用@Autowired+@Qualifier的效果

        @Resource(name = "userDao")
        private Dao userDao;

    name属性指向的是bean的id属性

    3.2@Autowired

    可以单独使用@Autowired。

    @Autowired
    private Dao userDao;

    这个注解直接按照数据类型useDao在spring容器中进行匹配,在spring中找userDao的bean,如果找到了直接注入到该属性中,但是如果spring中有多个userDao的bean,就不知道注入哪个了。

    3.3@Qualifier

    这个注解需要搭配@Autowired一起使用

        @Autowired
        @Qualifier("userDao")
        private useDao userDao;

    这时候@Qualifier里面的字符串是值bean标签的id属性,即此时是根据id值跟容器中的值进行匹配,如果spring容器里面有多个同类对象,可以通过唯一标识id注入。

    4、注入普通属性

    @Value("gdut")
    private string school;

    这个注解考虑如下使用场景:

    配置文件中载入了一个properties文件,里面放着关于数据源的相关信息:

    <!--加载外部的properties文件-->
        <context:property-placeholder location="classpath:jdbc.properties"/>
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://localhost:3306/test
    jdbc.username=root
    jdbc.password=root

    如果是在配置文件中载入这些数据是通过以下的bean标签:

        <bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
            <property name="driverClass" value="${jdbc.driver}"></property>
            <property name="jdbcUrl" value="${jdbc.url}"></property>
            <property name="user" value="${jdbc.username}"></property>
            <property name="password" value="${jdbc.password}"></property>
        </bean>

    通过${key},就可以获得properties文件中对应的value

    在Java类中使用该bean:

    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    DataSource dataSource = app.getBean(DataSource.class);
    Connection connection = dataSource.getConnection();
    System.out.println(connection);
    connection.close();

    而如果使用value注解,则可以直接获得对应的value值:

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

    5、新注解

     5.1@Configuration、@ComponentScan、@Import

    //标志该类是Spring的核心配置类
    @Configuration
    //<context:component-scan base-package="com.itheima"/>
    @ComponentScan("com.itheima")
    //<import resource=""/>
    @Import({DataSourceConfiguration.class})
    public class SpringCofiguration {
    
    }

     思想的转换:使用一个Java类去代替applicationContext.xml

    5.2@PropertySource、@Bean

    //<context:property-placeholder location="classpath:jdbc.properties"/>
    @PropertySource("classpath:jdbc.properties")
    public class DataSourceConfiguration {
    
        @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("dataSource")  //Spring会将当前方法的返回值以指定名称存储到Spring容器中
        public DataSource getDataSource() throws PropertyVetoException {
            ComboPooledDataSource dataSource = new ComboPooledDataSource();
            dataSource.setDriverClass(driver);
            dataSource.setJdbcUrl(url);
            dataSource.setUser(username);
            dataSource.setPassword(password);
            return dataSource;
        }

    展开全文
  • Spring 依赖注入详解

    千次阅读 2020-07-14 11:28:18
    2. IOC的作用3.Spring依赖注入的几种方式构造函数注入Set方式注入集合方式注入4.Spring的自动装配 – 依赖注入 1.什么是Spring的依赖注入? 依赖注入,是IOC的一个方面,是个通常的概念,它有多种解释。这概念是说你...

    一、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 事务详解


    如果有收获!!! 希望老铁们来个三连,点赞、收藏、转发
    创作不易,别忘点个赞,可以让更多的人看到这篇文章,顺便鼓励我写出更好的博客
    展开全文
  • Spring实现依赖注入的几种方式

    千次阅读 2022-02-07 14:32:03
    Spring实现依赖注入的几种方式 1.基于有参构造实现 <bean id="user" class="com.ccu.twj"> <constructor-arg name="name" value="张三"></constructor-arg> <constructor-arg name="age" ...

    Spring实现依赖注入的几种方式

    1.基于有参构造实现

        <bean id="user" class="com.ccu.twj">
            <constructor-arg name="name" value="张三"></constructor-arg>
            <constructor-arg name="age" value="18"></constructor-arg>
        </bean>
    

    使用 constructor-arg 标签注入属性值,其中id为唯一标识,class为类的全路径。name为属性名称,value为属性值。

    2.基于set方法实现

        <bean id="user" class="com.ccu.twj">
            <property name="name" value="李四"></property>
            <property name="age" value="18"></property>
        </bean>
    

    使用 property 标签注入属性值,name为属性名称,value为属性值。

    3.基于命名空间实现

    3.1 p 命名空间注入

           是 set方法注入 的一种快捷实现方式

    	<!--需要加入下面的名称空间-->
    	xmlns:c="http://www.springframework.org/schema/p"
        <bean id="Bean 唯一标志符" class="包名+类名" p:普通属性="普通属性值" p:对象属性-ref="对象的引用">
    
    3.2 c 命名空间注入

           是 构造函数注入 的一种快捷实现方式

    		<!--需要加入下面的名称空间-->
    	xmlns:c="http://www.springframework.org/schema/c"
        <bean id="Bean 唯一标志符" class="包名+类名" c:普通属性="普通属性值" c:对象属性-ref="对象的引用">
    

    4.基于注解实现

    1. @Autowired 注解默认按照 Bean 的类型进行装配,默认情况下它要求依赖对象必须存在,如果允许 null 值,可以设置它的 required 属性为 false。如果我们想使用按照名称(byName)来装配,可以结合 @Qualifier 注解一起使用@Autowired

    2. @Qualifier 与 @Autowired 注解配合使用,会将默认的按 Bean 类型装配修改为按 Bean 的实例名称装配,Bean 的实例名称由 @Qualifier 注解的参数指定。
      @Qualifier

    3. @Resource 按名称或类型自动装配,需要第三方包 javax.annotation.jar 的支持,只能标注在成员变量、setter方法上。作用与 Autowired 相同,区别在于 @Autowired 默认按照 Bean 类型装配,而 @Resource 默认按照 Bean 的名称进行装配。

     @Resource 中有两个重要属性:name 和 type。
        Spring 将 name 属性解析为 Bean 的实例名称,type 属性解析为 Bean 的实例类型。
        如果指定 name 属性,则按实例名称进行装配;
        如果指定 type 属性,则按 Bean 类型进行装配;
        如果都不指定,则先按 Bean 实例名称装配,如果不能匹配,则再按照 Bean 类型进行装配;如果都无法匹配,则抛出 NoSuchBeanDefinitionException 异常。
    

    @Resource 根据名称注入@Resource 根据类型注入

    1. @Inject 与@Autowired类似,可以完全代替@Autowired,但这个没有required属性,要求bean必须存在。如果要按名称装配,需要结合javax另外一个注解Named使用。
      @Inject 根据类型注入
      @Inject 根据名称注入
    展开全文
  • spring依赖注入三种方式

    千次阅读 2022-06-08 13:33:12
    spring依赖注入
  • 什么是Spring依赖注入

    千次阅读 2019-11-14 11:53:21
    参考文档 ...什么是Spring依赖注入?...spring依赖注入对调用者和被调用者几乎没有任何要求,完全支持pojo之间依赖关系的管理 new对象:类的头部进行实例化对象和依赖注入一个效果,这个时候该...
  • Spring依赖注入的三种方式

    千次阅读 2021-10-26 21:10:16
    Spring依赖注入,我们一般使用@Autowired注解来完成,关于依赖注入一般有三种方式: 变量注入、构造器注入、setter方法注入,下面我们仔细分析一下三种注入方式各自的特点以及使用场景。 一、变量注入(Field ...
  • 有4种依赖注入方式: Set方法注入:注入是最简单、最常用的注入方式,支持注解+xml。 构造器注入:是指带有参数的构造函数注入,支持注解+xml。 静态工厂的方法注入:通过调用静态工厂的方法来获取自己需要的对象...
  • Spring 使用注解实现依赖注入

    千次阅读 2020-10-08 17:35:38
    Spring 使用注解实现依赖注入 依赖注入:本质就是类中的变量进行赋值操作! spring 使用注解标注类,spring容器通过包扫描注解,将这些标注了spring注解的类管理起来。 1、@service注解: ​ 标注在一个service层...
  • Spring依赖注入(注解方式)

    千次阅读 2021-05-13 12:13:38
    Spring依赖注入(注解方式) 在Spring中,尽管使用XML配置文件就可以实现Bean的装配工作,但如果应用中Bean的数量较多,会导致XML配置文件过于臃肿,从而给程序的维护与升级带来一定的困难。 Java从JDK5.0以后,提供...
  • Spring依赖注入实现简单工厂模式

    千次阅读 热门讨论 2019-03-18 14:46:55
      这个也比较容易理解,因为Spring注入是在项目启动的时候执行的,所以后期new出来的实例对象中的注入注解就不会生效了。 举个例子:   假设有一个订单支付功能,我们有两种支付方式,一种支付宝支付,一种...
  • 将被依赖对象通过构造函数的参数注入依赖对象,并且在初始化对象的时候注入。 优点: 对象初始化完成后便可获得可使用的对象。 缺点: 当需要注入的对象很多时,构造器参数列表将会很长; 不够灵活。若有多种注入...
  • Spring源码剖析——依赖注入实现原理

    万次阅读 多人点赞 2016-08-06 09:35:00
    引言  在之前的 Spring源码剖析——核心IOC容器原理这篇文章中,已经详细介绍了在Spring当中我们配置的Bean是怎样被Spring解析和管理的,我们配置的那些Bean经过 载入 、解析 和 注册 这三个过程后,在框架内部被...
  • spring 依赖注入的三种实现方式

    万次阅读 2016-12-17 22:31:36
    二,依赖注入的三种实现方式? 1.接口注入 2.set注入 3.构造注入 接口注入:指的就是在接口中定义要注入的信息,并通过接口完成注入。 关于实现接口注入的例子,步骤如下: (1)编写一个接口IBusiness,各种...
  • Spring依赖注入与自动装配

    万次阅读 2021-02-06 11:13:29
    Spring依赖注入与自动装配 首先推荐狂神说的Spring讲义 1.Beans.xml作用 简而言之,我们通过在beans.xml中进行配置,将各种类交给spring来管理。 2.依赖注入 推荐狂神说Spring03:依赖注入(DI) 这要从控制反转说起...
  • spring依赖注入的3种实现方式

    千次阅读 2018-08-10 22:05:15
    依赖注入的3种实现方式分别是:接口注入(interface injection)、Set注入(setter injection)和构造注入(constructor injection)。   接口注入(interface injection)  接口注入指的就是在接口中定义要注入...
  • spring依赖注入的三种方式以及优缺点 一.依赖注入的三种方式 1.通过构造器注入。(spring4.3之后,推荐使用) 2.通过setter注入。(spring4.3之前,推荐使用) 3通过filed注入。 二.三种方式的代码示例: ...
  • Spring积累(3):依赖注入3种方式

    千次阅读 2021-08-08 16:12:08
    如果用@Resource进行依赖注入,它先会根据指定的name属性去Spring容器中寻找与该名称匹配的类型,例如:@Resource(name="commonDao"),如果没有找到该名称,则会按照类型去寻找,找到之后,会字段commonDao进行...
  • 首先有一个接口,包含了三个实现类。 2、三个实现类分别重写其中一个...其中map的key就是实现类的类名,value就是依赖注入的类 4、具体使用 通过map直接get类名,就能获取到当前想使用的子类。 ......
  • spring依赖注入原理详解

    千次阅读 2016-08-16 09:23:52
    spring依赖注入原理详解
  • Spring依赖注入

    万次阅读 2018-01-10 11:49:42
    Spring框架的核心功能之一就是通过依赖注入的方式来管理Bean之间的依赖关系。那么我们今天的主角依赖注入到底有什么神奇之处呢?请往下继续看。 了解过设计模式的朋友肯定知道工厂模式吧,即所有的对象的创建都交给...
  • Spring依赖注入的三种实现方式

    千次阅读 2020-03-27 06:57:58
    依赖注入(Dependency Injection,DI)和控制反转含义相同,它们是从两个角度描述的同一个概念。 当某个JAVA实例需要另一个 Java 实例时,传统的方法是由调用者创建被调用者的实例(例如,使用 new 关键字获得被调用...
  • spring四种依赖注入方式

    万次阅读 多人点赞 2019-05-07 10:49:18
    spring提出了依赖注入的思想,即依赖不由程序员控制,而是通过spring容器帮我们new指定实例并且将实例注入到需要该对象的类中。依赖注入的另一种说法是“控制反转”,通俗的理解是:平常我们new一个实例,这个实例的...
  • DI (Dependency Injection):依赖注入是指在 Spring IOC 容器创建对象的过程中,将所 依赖的对象通过配置进行注入。我们可以通过依赖注入的方式来降低对象间的耦合度。 在软件工程中,对象之间的耦合度就是...
  • Spring支持两种依赖注入方式,分别是属性注入,构造函数注入。除此之外,Spring还支持工厂注入方式。 接下来,我们一起来了解一下Spring的几种注入方式。 一.属性注入 首先来了解一下定义:属性注入是指通过 ...
  • 在我们写代码的过程中,通常会用new来产生一个对象,但是这样操作的后果会使得代码难于管理。 而Spring框架为我们提供了一个控制...而依赖注入(DI,Dependency Injection)就是实现控制反转的其中一种方式。 一...
  • Spring依赖注入原理浅析

    千次阅读 2019-01-10 12:02:57
    Spring依赖注入依靠了动态代理和反射 最初我认为Spring的扫包时通过反射实例化了类,但是有个问题一直想不通 就是反射的方式获取实例时有可能会抛出异常,但是在手动获取Spring管理的对象时却不需要捕捉异常,...
  • Spring依赖注入(接口注入)

    千次阅读 2017-04-14 10:58:56
    Spring依赖注入(接口注入)  2009-11-26 10:06 148人阅读 评论(0) 收藏 举报   这篇文章来谈谈《Spring Framework 开发参考手册》的3.3.3.1小节中的Lookup方法注入。     仔细看看文档,这种方法...
  • spring依赖注入对象为null

    千次阅读 2018-03-29 23:13:05
    前不久帮一个同事调试一段代码,发现注入对象为null 被注解的对象如下: @Component public class SparkSource{ @Autowired private SparkConfig sparkConfig ; @Autowired private Redi...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 253,849
精华内容 101,539
热门标签
关键字:

对spring依赖注入的实现解释

spring 订阅