引入

程序的耦合:

程序间的依赖关系:类之间的依赖,方法之间的依赖

解耦合:降低程序间的依赖关系(尽量做到编译器不依赖,运行时才依赖)

解耦方式:

  1. 使用反射创建类对象,避免使用new关键字
  2. 通过读取配置文件来获取要创建的对象全限定类名

Spring基于XML的开发

1.导入坐标依赖

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

2.编写Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

3.导入Spring的配置文件

ApplicationContext的三个实现类:

  1. ClassPathXmlApplicationContext:
  2. FileSystemXmlApplicationContext:
  3. AnnotationConfigApplicationContext:

4.Spring的依赖注入

  1. 构造函数注入:

    标签:constructor-arg

    标签出现的位置:bean标签的内部

    常用标签的属性:

    (1)name:给指定构造函数中指定名称的参数赋值

    (2)value:用于提供基本类型和String类型的数据

    (3)ref:用于指定其他的bean类型数据。它指的是在Spring的IOC核心容器中出现过的bean对象

    <bean id="accountService" class="com.service.Impl.AccountImpl">
        <constructor-arg name="name" value="张三"></constructor-arg>
        <constructor-arg name="age" value="20"></constructor-arg>
        <constructor-arg name="birthday" ref="now"></constructor-arg>
    </bean>
   package com.service.Impl;

   import com.Dao.IAccountDao;
   import com.Dao.Impl.AccountDaoImpl;
   import com.service.IAccountService;

   import java.text.DateFormat;
   import java.util.Date;

   public class AccountImpl implements IAccountService {

       private String name;
       private int age;
       private Date birthday;

       public AccountImpl(String name, int age, Date birthday) {
           this.name = name;
           this.age = age;
           this.birthday = birthday;
       }

       public void SaveAccount() {
           System.out.println(this.name + "   " + this.age + "   "+ this.birthday);
       }
   }

主方法测试

   package com;


   import com.service.IAccountService;
   import org.springframework.context.ApplicationContext;
   import org.springframework.context.support.ClassPathXmlApplicationContext;


   public class Demo {
       public static void main(String[] args) {
           ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
           IAccountService as = (IAccountService) ac.getBean("accountService");
           as.SaveAccount();
       }
   }
  1. set方法注入

    标签:property

    出现位置:bean标签内部

    标签的属性:

    (1)name:用于指定注入时所调用的set方法名称(去掉前面的Set然后小写)

    (2)value:用于提供基本类型和String类型的数据

    (3)ref:用于指定其他的bean类型数据。它指的是在Spring的IOC核心容器中出现过的bean对象,该数据类型需要先注入,然后在其他数据类型中通过,id注入。

3.注解方法注入

​ 下面详细介绍

5.Spring复杂数据类型的注入

  1. List集合注入的标签:list,array,set
  2. Map集合注入的标签:map,props

Spring基于注解的开发

1.创建对象的注解

Tip:首先要在XML配置文件中扫描注解

<context:component-scan base-package="被扫描的包名"></context:component-scan>
  • @Component:将当前类对象存入Spring容器

    ​ 属性:value:指定bean的id(默认id为首字母小写的类名)

  • @Controller(表现层),@Service(业务层)@Repository(持久层):这三个注解功能与属性与@Component一致,只是Spring框架提供的明确的三层架构

2.注入数据的注解

  • @Autowirted:自动按照类型注入

    对于Autowirted,注入时必须使用已经存在bean,如果同时存在两个实现类继承了一个接口,需要使用@Qualifier进行区分,或者根据类名进行区分

  • @Qualifier:在原注入基础上根据名称注入

    ​ 属性:value 用于指定

  • @Resource:直接根据bean的id注入

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

  • @Value:用于注入基本数据类型和String类型

    ​ 属性:value用于指定数据的值

3.改变作用范围的注解

  • @Scope

    ​ 属性:value用于指定范围取值(singleton[单例],prototype[多例])

Spring基于XML的开发案例

利用Spring使用JDBC以及Druid代理池,实现对数据库的增删查改

依赖导入

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>SpringDay02</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.23</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
    </dependencies>
</project>

Spring配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!-- 配置Service   -->
    <bean id="accountService" class="com.Service.Impl.AccountServiceImpl">
        <!--通过set方法注入accountDao -->
        <property name="accountDao" ref="accountDao"></property>
    </bean>
    <!--配置Dao-->
    <bean id="accountDao" class="com.Dao.Impl.AccountDaoImpl">
        <!--通过set方法注入JdbcTemplate-->
        <property name="jt" ref="jt"></property>
    </bean>
    <!--配置JdbcTemplate-->
    <bean id="jt" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--由于JdbcTemplate不提供set方法,所以这里提供构造方法注入dataSource-->
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    <!--配置DataSource-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <!--注入mysql的用户名 密码 url 驱动-->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///springdemo"></property>
        <property name="username" value="root"></property>
        <property name="password" value="sr20000316"></property>
    </bean>
</beans>

对于Spring基于XML的配置可以分为以下几个步骤:

1、配置类

2、对该类中的数据进行注入,具体是注入方式详见最上方

Account实体

package com.Bean;

import java.io.Serializable;

public class Account implements Serializable {
    private Integer id;
    private String name;
    private Integer money;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getMoney() {
        return money;
    }

    public void setMoney(Integer money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

IAccountService接口

package com.Service;

import com.Bean.Account;

import java.util.List;

public interface IAccountService {

    public List<Account> findall();

    public Account findAccountById();

    public void saveAccount(Account account);

    public void updateAccount(Account account);

    public void deleteAccount(Integer id);
}

IAccountService实现类

package com.Service.Impl;

import com.Bean.Account;
import com.Dao.IAccountDao;
import com.Service.IAccountService;

import java.util.List;

public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao;

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

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

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

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

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

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

IAccountDao接口

package com.Dao;

import com.Bean.Account;

import java.util.List;

public interface IAccountDao {
    public List<Account> findall();

    public Account findAccountById(Integer id);

    public void saveAccount(Account account);

    public void updateAccount(Account account);

    public void deleteAccount(Integer id);
}

IAccountDao接口实现类

package com.Dao.Impl;

import com.Bean.Account;
import com.Dao.IAccountDao;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.beans.BeanProperty;
import java.util.List;

public class AccountDaoImpl implements IAccountDao {

    private JdbcTemplate jt;

    public void setJt(JdbcTemplate jt) {
        this.jt = jt;
    }

    public List<Account> findall() {
        return jt.query("select* from account",new BeanPropertyRowMapper<Account>(Account.class));
    }

    public Account findAccountById(Integer id) {
        Object[] params = {id};
        List<Account> accounts = jt.query("select* from account where id = ?", params, new BeanPropertyRowMapper<Account>(Account.class));
        return accounts.get(0);
    }

    public void saveAccount(Account account) {
        Object[] params = {account.getId(),account.getName(),account.getMoney()};
        jt.update("insert into account values(?,?,?)",params);
    }

    public void updateAccount(Account account) {
        Object[] params = {account.getName(),account.getMoney(),account.getId()};
        jt.update("update account set name = ?,money = ? where id = ?",params);
    }

    public void deleteAccount(Integer id) {
        Object[] params = {id};
        jt.update("delete from account where id = ?",params);
    }

}

测试类

package com;

import com.Bean.Account;
import com.Service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class Demo {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService as =  (IAccountService) ac.getBean("accountService");
        //删除操作
        as.deleteAccount(2);
        Account account = new Account();
        account.setId(4);
        account.setMoney(3000);
        account.setName("王五");
        //新增操作
        as.saveAccount(account);
        //查找所有操作
        List<Account> accounts = as.findall();
        System.out.println(accounts);
        Account account2 = new Account();
        account2.setId(1);
        account2.setName("张三");
        account2.setMoney(30000);
        as.updateAccount(account2);
        //根据ID查找操作
        Account account1 = as.findAccountById(1);
        System.out.println(account1);

    }
}

Spring基于注解的开发案例

依赖注入

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>SpringDay02</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.21</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.7</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.23</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.2.8.RELEASE</version>
        </dependency>
    </dependencies>
</project>

IAccountService接口

package com.Service;

import com.Bean.Account;
import java.util.List;

public interface IAccountService {

    public List<Account> findall();

    public Account findAccountById(Integer id);

    public void saveAccount(Account account);

    public void updateAccount(Account account);

    public void deleteAccount(Integer id);
}

IAccountService实现类

package com.Service.Impl;

import com.Bean.Account;
import com.Dao.IAccountDao;
import com.Service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("accountService")
public class AccountServiceImpl implements IAccountService {
    @Autowired
    private IAccountDao accountDao;

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

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

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

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

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

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

IAccountDao接口

package com.Dao;

import com.Bean.Account;

import java.util.List;

public interface IAccountDao {
    public List<Account> findall();

    public Account findAccountById(Integer id);

    public void saveAccount(Account account);

    public void updateAccount(Account account);

    public void deleteAccount(Integer id);
}

IAccountDao实现类

package com.Dao.Impl;

import com.Bean.Account;
import com.Dao.IAccountDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Repository;

import java.util.List;

@Repository("accountDao")
public class AccountDaoImpl implements IAccountDao {
    @Autowired
    private JdbcTemplate jt;

    public List<Account> findall() {
        return jt.query("select* from account",new BeanPropertyRowMapper<Account>(Account.class));
    }

    public Account findAccountById(Integer id) {
        Object[] params = {id};
        List<Account> accounts = jt.query("select* from account where id = ?", params, new BeanPropertyRowMapper<Account>(Account.class));
        return accounts.get(0);
    }

    public void saveAccount(Account account) {
        Object[] params = {account.getId(),account.getName(),account.getMoney()};
        jt.update("insert into account values(?,?,?)",params);
    }

    public void updateAccount(Account account) {
        Object[] params = {account.getName(),account.getMoney(),account.getId()};
        jt.update("update account set name = ?,money = ? where id = ?",params);
    }

    public void deleteAccount(Integer id) {
        Object[] params = {id};
        jt.update("delete from account where id = ?",params);
    }

}

Spring配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        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"></context:component-scan>
    <bean id="jt" class="org.springframework.jdbc.core.JdbcTemplate">
        <!--由于JdbcTemplate不提供set方法,所以这里提供构造方法注入dataSource-->
        <constructor-arg name="dataSource" ref="dataSource"></constructor-arg>
    </bean>
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <!--注入mysql的用户名 密码 url 驱动-->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql:///springdemo"></property>
        <property name="username" value="root"></property>
        <property name="password" value="sr20000316"></property>
    </bean>
</beans>

Spring的配置类

从上面的基于注解实现的IOC案例中,可以发现,虽然使用注解创建了对象,但是我们仍然需要配置文件来创建那些不是我们自己写的类,所以这里就再次引入三个注解,这样就可以在使用注解时完全脱离XML配置文件

  • @Configuration:指定当前类为一个配置类

  • @ComponentScan:通过注解指定Spring的创建容器中要扫描的包

    ​ 属性:value/basePackages:扫描某一个包 下的全部注解

  • @bean:用于把当前方法的返回值作为bean对象存入Spring的IOC容器中

  • @Import

    ​ 属性:value:导入其他的配置类,有Import注解的类是主配置类

  • @PropertySource

    ​ 属性:value:指定文件的名称和路径;classpath表示类路径下

package com.Config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

@Configuration
@ComponentScan("com")
public class SpringConfiguration {
    @Bean(name = "jdbc")
    public JdbcTemplate creatJDBC(DataSource ds){
        return new JdbcTemplate(ds);
    }

    @Bean(name = "dataSource")
    public DataSource createDateSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.cj.jdbc.Driver");
        ds.setUsername("root");
        ds.setPassword("sr20000316");
        ds.setUrl("jdbc:mysql:///springdemo");
        return ds;
    }
}

当使用上面的三个注解以后,我们就可以完全脱离XML配置文件了,这里测试方法中要读取这个类

f恩别package com;

import com.Bean.Account;
import com.Config.SpringConfiguration;
import com.Service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class Demo {
    public static void main(String[] args) {
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfiguration.class);
        IAccountService as =  (IAccountService) ac.getBean("accountService");
        //删除操作
//        as.deleteAccount(2);
        Account account = new Account();
        account.setId(4);
        account.setMoney(3000);
        account.setName("王五");
        //新增操作
        as.saveAccount(account);
        //查找所有操作
        List<Account> accounts = as.findall();
        System.out.println(accounts);
        Account account2 = new Account();
        account2.setId(1);
        account2.setName("张三");
        account2.setMoney(30000);
        as.updateAccount(account2);
        //根据ID查找操作
        Account account1 = as.findAccountById(1);
        System.out.println(account1);
    }
}

实际开发中一般使用注解和XML混合使用

总结

在Spring中我们经常谈到注入的概念,这里的注入分为两种方式,一种是通过在xml文件中配置,一种是通过注解(bean),按照我的理解,注入其实就是,比如说你定义了一个对象Account account,通过注入的方式,Spring会知道你只要定义了这个Account,他就知道你使用的这个类型,不需要new,可以直接使用。但是这里要注意,如果有唯一匹配时,直接注入即可,但是如果有多个匹配,首先按照类型筛选出符合条件的对象,然后根据id(@bean(id)),分别匹配,如果有唯一对应就注入成功,否则注入失败