spring框架(一)

1、Spring框架:IoC和AOP

服务端三层开发:表现层、业务层、持久层 ssm, springboot, springcloud(微服务,治理组件)

Spring框架是一个流行的Java应用程序框架,它提供了许多功能来简化企业级应用程序的开发。其中,控制反转(Inversion of Control,IoC)和面向切面编程(Aspect-Oriented Programming,AOP)是Spring框架的两个重要概念。

1.控制反转(IoC):将对象的创建权力反转给Spring框架

控制反转是一种设计原则,旨在将控制权从代码中提取出来,并交由外部容器或框架来管理。在传统的程序设计中,对象之间的依赖关系通常是在代码中硬编码的,这会导致代码之间的耦合度较高,不利于维护和扩展。通过控制反转,依赖关系的管理被抽象到一个外部容器或框架中,从而降低了代码之间的耦合度。

在Spring框架中,IoC通过依赖注入(Dependency Injection,DI)的方式来实现。DI是一种将一个对象的依赖关系注入到该对象中的技术。通过使用IoC容器,开发者可以声明对象的依赖关系,而IoC容器会在运行时自动将这些依赖关系注入到对象中。这种方式使得对象的创建和依赖关系的配置更加灵活和可维护。

  1. 面向切面编程(AOP):

面向切面编程是一种编程范式,旨在将应用程序中的横切关注点(cross-cutting concerns)从业务逻辑中分离出来。横切关注点是指跨多个模块或组件的通用功能,例如日志记录、事务管理、安全等。在传统的程序设计中,这些横切关注点通常会与业务逻辑混杂在一起,导致代码难以维护和扩展。

AOP通过定义"切面"来将横切关注点从业务逻辑中分离出来。一个切面可以定义为一个跨越多个模块或组件的横切关注点的集合。通过使用AOP,开发者可以将通用功能封装在独立的模块或组件中,并在需要时将其应用于业务逻辑。这种方式可以提高代码的可维护性和可重用性,并减少代码的冗余。

在Spring框架中,AOP通过代理模式来实现。代理模式是一种设计模式,其中客户端通过代理对象来访问目标对象。通过使用代理模式,Spring框架可以在运行时动态地将横切关注点应用到业务逻辑中。

2、Spring框架的优点

1.方便解耦,简化开发,Spring就是一个大工厂,可以将所有对象创建和依赖关系维护,交给Spring管理。IOC的作用。

2.AOP编程的支持,Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能。(可扩展性)

3.声明式事务的支持,只需要通过配置就可以完成对事务的管理,而无需手动编程。

4.方便程序的测试,Spring对Junit4支持,可以通过注解方便的测试Spring程序。

5.方便集成各种优秀框架,Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts2、Hibernate、MyBatis、Quartz等)的直接支持。

6.降低JavaEE API的使用难度,Spring 对JavaEE开发中非常难用的一些API(JDBC、JavaMail、远程调用等),都提供了封装,使这些API应用难度大大降低。

3、IOC程序简单示例

创建Java工程,导入坐标依赖pom.xml

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

        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>

        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.12</version>
        </dependency>

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

编写接口和实现类,编写具体的实现方法

java 复制代码
package com.qcby.service;
public interface UserService {
    public void hello();
}

​

package com.qcby.service;
public class UserServiceImpl implements UserService {
    @Override
    public void hello() {
        System.out.println("Hello IOC!!");
    }
}

编写Spring核心的配置文件,在src目录下创建applicationContext.xml的配置文件,名称是可以任意的,但是一般都会使用默认名称。

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


​
<!--IOC管理bean-->
    <bean id="userService" class="com.qcby.service.UserServiceImpl" />
</beans>

编写测试方法

java 复制代码
package com.qcby.test;
import com.qcby.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Demo {
    /**
     * 入门程序
     */
    @Test
    public void run(){
        // 使用Spring的工厂
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 通过工厂获得类:
        UserService userService = (UserService) applicationContext.getBean("userService");
        userService.hello();
    }
}

IOC技术总结

ApplicationContext接口,工厂的接口,使用该接口可以获取到具体的Bean对象。该接口下有两个具体的实现类。

ClassPathXmlApplicationContext,加载类路径下的Spring配置文件。

FileSystemXmlApplicationContext,加载本地磁盘下的Spring配置文件。

4、Spring框架的Bean管理的配置文件方式

id属性,Bean起个名字,在约束中采用ID的约束,唯一,取值要求:必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号 id:不能出现特殊字符。

class属性,Bean对象的全路径。

scope属性,scope属性代表Bean的作用范围。 singleton单例(默认值),最常用的方式; prototype多例

​ request应用在Web项目中,每次HTTP请求都会创建一个新的Bean

​ session应用在Web项目中,同一个HTTP Session 共享一个Bean

Bean对象的创建和销毁的两个属性配置

说明:Spring初始化bean或销毁bean时,有时需要作一些处理工作,因此spring可以在创建和拆卸bean的时候调用bean的两个生命周期方法

init-method,当bean被载入到容器的时候调用init-method属性指定的方法

destroy-method,当bean从容器中删除的时候调用destroy-method属性指定的方法

单例的对象销毁:跟着容器工厂关闭才销毁

多例的对象销毁:垃圾回收机制进行回收的

实例化Bean对象的三种方式

①默认是无参数的构造方法(默认方式,基本上使用)

java 复制代码
<bean id="us" class="com.qcby.service.UserServiceImpl" />

②静态工厂实例化方式

java 复制代码
package com.qcby.demo1;
import com.qcby.service.UserService;
import com.qcby.service.UserServiceImpl;

​/**
  * 静态工厂方式
 */
public class StaticFactory {
    // 静态工厂方式
    public static UserService createUs(){
        System.out.println("通过静态工厂的方式创建UserServiceImpl对象...");
        // 编写很多业务逻辑 权限校验
        return new UserServiceImpl();
    }
}

<bean id="us" class="com.qcby.demo1.StaticFactory" factory-method="createUs" />        

③动态工厂实例化方式

java 复制代码
package com.qcby.demo1;
import com.qcby.service.UserService;
import com.qcby.service.UserServiceImpl;
/**
  *
 * 动态工厂方式
 *
 */
public class Dfactory {
    public UserService createUs(){
        System.out.println("实例化工厂的方式...");
        return new UserServiceImpl();
    }
}


<bean id="dfactory" class="com.qcby.demo1.Dfactory" />
<bean id="us" factory-bean="dfactory" factory-method="createUs" />

4、DI依赖注入

IOC和DI的概念

​ IOC:Inverse of Control,控制反转,将对象的创建权反转给Spring

​ DI:Dependency Injection,依赖注入,在Spring框架负责创建Bean对象时,动态的将依赖对象注入到Bean组件中

①属性的set方法注入值

编写属性,提供该属性对应的set方法,编写配置文件完成属性值的注入

java 复制代码
package com.qcby.service;

public class Person {
    // 编写成员属性,一定需要提供该属性的set方法
    private String name;
    private Integer age;
    private Car car;

    // 一定需要提供该属性的set方法,IOC容器底层就通过属性的set方法方式注入值
    public void setName(String name) {
        this.name = name;
    }

    public void setAge(Integer age) {
        this.age = age;
    }

    public void setCar(Car car) {
        this.car = car;
    }

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

​
package com.qcby.service;
public class Car {
    // 名称
    private String cname;
    // 金额
    private Double money;

    public void setCname(String cname) {
        this.cname = cname;
    }

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

    @Override
    public String toString() {
        return "Car{" +
                "cname='" + cname + '\'' +
                ", money=" + money +
                '}';
    }
}


    <!--DI:依赖注入-->
<bean id="person" class="com.qcby.service.Person">
    <property name="car" ref="car" />
    <property name="name" value="张三" />
    <property name="age" value="30" />
</bean>

<bean id="car" class="com.qcby.service.Car">
    <property name="cname" value="奥迪" />
    <property name="money" value="300000.00" />
</bean>

②属性构造方法方式注入值

对于类成员变量,构造函数注入。

java 复制代码
package com.qcby.domain;
public class Car {
    // 名称
    private String cname;
    // 金额
    private Double money;
    public Car(String cname, Double money) {
        this.cname = cname;
        this.money = money;
    }
    
    @Override
    public String toString() {
        return "Car{" +
                "cname='" + cname + '\'' +
                ", money=" + money +
                '}';
    }
}
​
<bean id="car" class="com.qcby.demo2.Car">
    <constructor-arg name="cname" value="大奔" />
    <constructor-arg name="money" value="400000" />
 </bean>

③数组,集合(List,Set,Map),Properties等的注入

java 复制代码
package com.qcby.domain;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;
​
public class CollectionBean {
    // 数组
    private String [] strs;
    public void setStrs(String[] strs) {
        this.strs = strs;
    }
    
    private List<String> list;
    public void setList(List<String> list) {
        this.list = list;
    }

    private Map<String,String> map;
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    private Properties properties;
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    
    @Override
    public String toString() {
        return "CollectionBean{" +
                "strs=" + Arrays.toString(strs) +
                ", list=" + list +
                ", map=" + map +
                ", properties=" + properties +
                '}';
    }
}

    <!--给集合属性注入值-->
    <bean id="collectionBean" class="com.qcby.demo3.CollectionBean">
        <property name="strs">
            <array>
                <value>美美</value>
                <value>小凤</value>
            </array>

        </property>
        <property name="list">
            <list>
                <value>熊大</value>
                <value>熊二</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="aaa" value="老王"/>
                <entry key="bbb" value="小王"/>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="username">root</prop>
                <prop key="password">123456</prop>
            </props>
        </property>
    </bean>

5、多配置文件方式

在src的目录下又多创建了一个配置文件,现在是两个核心的配置文件,那么加载这两个配置文件的方式有两种!

java 复制代码
主配置文件中包含其他的配置文件:
<import resource="applicationContext2.xml"/>

工厂创建的时候直接加载多个配置文件:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(
"applicationContext.xml","applicationContext2.xml");

6、Spring框架开发程序的方式

① Spring框架开发方式

1) 需求:编写service和dao的类,演示代码

2) 技术选择:持久层使用原始的JDBC的程序,连接池选择的是Druid连接池。创建maven工程,导入开发的jar包

java 复制代码
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.0.2.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>

        <!--连接池-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.10</version>
        </dependency>
        <!--mysql驱动包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.6</version>
        </dependency>
    </dependencies>

创建数据库,创建表结构

java 复制代码
create database spring_db;
use spring_db;
create table account(
    id int primary key auto_increment,
    name varchar(40),
    money double
)character set utf8 collate utf8_general_ci;
​
insert into account(name,money) values('aaa',1000);
insert into account(name,money) values('bbb',1000);
insert into account(name,money) values('ccc',1000);

编写JavaBean的类

java 复制代码
package com.qcby.domain;
import java.io.Serializable;

public class Account implements Serializable {
    private static final long serialVersionUID = 7355810572012650248L;
    private Integer id;
    private String name;
    private Double 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 Double getMoney() {
        return money;
    }

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

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

编写AccountDao的接口和实现类

java 复制代码
package com.qcby.dao;
import com.qcby.domain.Account;
import java.util.List;
public interface AccountDao {
    public List<Account> findAll();
}

package com.qcby.dao;
import com.qcby.domain.Account;
import com.alibaba.druid.pool.DruidDataSource;
import javax.sql.DataSource;​
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

public class AccountDaoImpl implements AccountDao {  
//不使用连接池
//1、加载驱动
//2、获取连接
//3、编写sql
//4、预编译sql
//5、设置值
//6、执行sql 拿到结果集
//7、遍历结果集关闭资源
//        String driver = "com.mysql.jdbc.Driver";
//        String url="jdbc:mysql://localhost:3306/spring_db?useUnicode=true&characterEncoding=UTF-8";
//        String user = "root";
//        String password = "123456";
//        String sql = "select * from account";
//        List<Account> res = new ArrayList<Account>();
//        Class.forName(driver);
//        Connection conn = (Connection) DriverManager.getConnection(url, user, password);
//        Statement stmt = (Statement) conn.createStatement();
//        ResultSet rs = (ResultSet) stmt.executeQuery(sql);
//        while(rs.next()){
//            Account acc = new Account();
//            acc.setId(rs.getInt("id")); //获取id字段的值并设置到Account对象中
//            acc.setName(rs.getString("name")); //获取name字段的值并设置到Account对象中
//            acc.setMoney(rs.getDouble("money")); //获取money字段的值并设置到Account对象中
//            res.add(acc);
//        }
//        conn.close();
//        stmt.close();
//        rs.close();
//        return res;

 // 注入连接池对象
   private DataSource dataSource;
   public void setDataSource(DataSource dataSource) {
       this.dataSource = dataSource;
   }​

   /**
    * 查询所有的数据
    * @return
    */
   @Override
   public List<Account> findAll() {
       /*
       DruidDataSource dataSource = new DruidDataSource();
       dataSource.setDriverClassName("com.mysql.jdbc.Driver");
       dataSource.setUrl("jdbc:mysql:///spring_db");
       dataSource.setUsername("root");
       dataSource.setPassword("123456");
       */
       List<Account> list = new ArrayList<>();
​       Connection connection = null;
       PreparedStatement stmt = null;
       ResultSet rs = null;
       try {
           // 获取连接
           connection = dataSource.getConnection();
           // 编写sql语句
           String sql = "select * from account";
           // 预编译
           stmt = connection.prepareStatement(sql);
           // 查询
           rs = stmt.executeQuery();
           // 遍历,封装数据
           while (rs.next()){
               Account account = new Account();
               account.setId(rs.getInt("id"));
               account.setName(rs.getString("name"));
               account.setMoney(rs.getDouble("money"));
               list.add(account);
           }
       } catch (SQLException e) {
           e.printStackTrace();
       }finally {
           try {
               connection.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
           try {
               stmt.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
           try {
               rs.close();
           } catch (SQLException e) {
               e.printStackTrace();
           }
       }
       return list;
   } 
 }
java 复制代码
package com.qcby.service;
import com.qcby.domain.Account;
import java.util.List;
public interface AccountService {
    public List<Account> findAll();
}

​package com.qcby.service;
import com.qcby.dao.AccountDao;
import com.qcby.domain.Account;
import java.util.List;

public class AccountServiceImpl implements AccountService {
    // 依赖注入
    private AccountDao accountDao;
    public void setAccountDao(AccountDao accountDao) {
       this.accountDao = accountDao;
    }

   /**
    * 查询所有的数据
    * @return
    */
   @Override
   public List<Account> findAll() {
       return accountDao.findAll();
   }
}

编写配置文件

java 复制代码
<?xml version="1.0"
encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
                    http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd">
                    
    <!--配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver" />
        <property name="url" value="jdbc:mysql:///spring_db" />
        <property name="username" value="root" />
        <property name="password" value="123456" />
    </bean>

    <!--管理bean-->
    <bean id="accountService" class="com.qcby.service.AccountServiceImpl">
        <property name="accountDao" ref="accountDao" />
    </bean>
    <bean id="accountDao" class="com.qcby.dao.AccountDaoImpl">
        <property name="dataSource" ref="dataSource" />
    </bean>
</beans>

编程测试程序

java 复制代码
package com.qcby.test;​
import com.qcby.domain.Account;
import com.qcby.service.AccountService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.List;

public class Demo1 {
    @Test
    public void run1(){
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        AccountService accountService = (AccountService) ac.getBean("accountService");
        // 调用方法
        List<Account> list = accountService.findAll();
        for (Account account : list) {
            System.out.println(account);
        }
    }
}

7、IOC注解的方式

① IOC注解方式的简单示例

IOC注解的方式依赖没有变化

编写接口和实现类

java 复制代码
package com.qcby.service;

public interface UserService {
    public void hello();​
}

package com.qcby.service;
import org.springframework.stereotype.Component;
/**
 * <bean id="us" class="com.qcby.demo2.UserServiceImpl" />
 */
// 组件,作用:把当前类使用IOC容器进行管理,如果没有指定名称,默认使用类名,首字母是小写。userServiceImpl。或者自己指定名称

@Component(value = "us")
public class UserServiceImpl implements UserService {
​    @Override
    public void hello() {
        System.out.println("Hello IOC注解...");
    }
}

在需要管理的类上添加@Component注解

java 复制代码
@Component(value = "us")
public class UserServiceImpl implements UserService {
    @Override
    public void hello() {
        System.out.println("Hello IOC注解...");
    }
}

编写配置文件,重点是开启注解扫描。

java 复制代码
<?xml version="1.0"
encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
                    http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd">
                    
    <!--开启注解扫描
    <context:component-scan base-package="com.qcby.demo2" />
    -->
    
    <!--开启注解扫描 com.qcby.所有的包中的所有的类 -->
    <context:component-scan base-package="com.qcby" />
</beans>

编写测试方法

java 复制代码
package com.qcby.test;
import com.qcby.service.UserService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Demo2 {
    /**
     * IOC注解方式的入门
     */

    @Test
    public void run1(){
        // 工厂
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext_anno.xml");
        // 获取对象
        UserService userService = (UserService) ac.getBean("us");
        userService.hello();
    }
}

② 常用的注解

bean管理类常用的4个注解(作用相同,推荐使用在不同分层上)

​ @Component 普通的类,任何地方

​ @Controller 表现层

​ @Service 业务层

​ @Repository 持久层

依赖注入常用的注解

​ @Value 用于注入普通类型(String,int,double等类型),可以省略

​ @Autowired 默认按类型进行自动装配(引用类型)

​ @Qualifier 和@Autowired一起使用,强制使用名称注入

​ @Resource Java提供的注解,也被支持。使用name属性,按名称注入对象生命周期(作用范围)注解

​ @Scope 生命周期注解,取值singleton(默认值,单实例)和prototype(多例)

初始化方法和销毁方法注解(了解)

​ @PostConstruct 相当于init-method

​ @PreDestroy 相当于destroy-method

单例的销毁时机是跟随容器的 容器销毁对象销毁

多例的销毁时机是java的垃圾回收机制控制的

具体的代码如下

java 复制代码
package com.qcby.domain;​
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Repository;
import org.springframework.stereotype.Service;​
import javax.annotation.PostConstruct;
import javax.annotation.Resource;

// 默认当前类名就是ID名称,首字母小写
@Component(value = "c")
// @Controller
// @Service(value = "c")
// @Repository(value = "c")
// @Scope(value = "singleton")     // 默认值,单例的
// @Scope(value = "prototype")         // 多例的
public class Car {
    // 注解注入值,属性set方法是可以省略不写的。
    // 只有一个属性,属性的名称是value,value是可以省略不写的
    @Value("大奔2")
    private String cname;
    @Value(value = "400000")
    private Double money;
    // 也不用提供set方法
    // 按类型自动装配的注解,和id名称没有关系
    @Autowired
    // 按id的名称注入,Qualifier不能单独使用,需要Autowired一起使用。
    // @Qualifier(value = "person")
    // @Resource Java提供的注解,按名称注入对象,属性名称是name
    // @Resource(name = "person")
    private Person person;
​    /**
     * Car对象创建完成后,调用init方法进行初始化操作
     */
    @PostConstruct
    public void init(){
        System.out.println("操作...");
    }
    /*
    public String getCname() {
        return cname;
    }
    public void setCname(String cname) {
        this.cname = cname;
    }
​    public Double getMoney() {
        return money;
    }
    public void setMoney(Double money) {
        this.money = money;
    }
    */

    @Override
    public String toString() {
        return "Car{" +
                "cname='" + cname + '\'' +
                ", money=" + money +
                ", person=" + person +
                '}';
    }
}

​package com.qcby.domain;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
​
@Component(value = "person")
public class Person {
​    @Value("张三")
    private String pname;
    @Override
    public String toString() {
        return "Person{" +
                "pname='" + pname + '\'' +
                '}';
    }
}

package com.qcby.test;
import com.qcby.service.UserService;
import com.qcby.domain.Car;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Demo3 {
    @Test
    public void run1(){
        // 工厂
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext_anno.xml");
        // 获取对象
        Car car = (Car) ac.getBean("c");
        System.out.println(car);
    }
}

③ IOC纯注解的方式

纯注解的方式是微服务架构开发的主要方式,所以也是非常的重要。纯注解的目的是替换掉所有的配置文件。但是需要编写配置类。

编写实体类

java 复制代码
package com.qcby.domain;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component
public class Order {
​    @Value("北京")
    private String address;
    
    @Override
    public String toString() {
        return "Order{" +
                "address='" + address + '\'' +
                '}';
    }
}

编写配置类,替换掉applicationContext.xml配置文件

java 复制代码
package com.qcby.domain;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
 * Spring的配置类,替换掉applicationContext.xml
 *
 */
// 声明当前类是配置类
@Configuration
// 扫描指定的包结构
@ComponentScan(value = "com.qcby")
public class SpringConfig {
}

测试方法的编写

java 复制代码
package com.qcby.test;
import com.qcby.domain.Order;
import com.qcby.domain.SpringConfig;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Demo4 {
    /**
     * 编写程序,需要加载配置类
     */
    @Test
    public void run(){
        // 创建工厂,加载配置类
        ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        // 获取到对象
        Order order = (Order) ac.getBean("order");
        System.out.println(order);
    }
}

常用的注解总结

@Configuration 声明是配置类

@ComponentScan 扫描具体包结构的

@Import注解 Spring的配置文件可以分成多个配置的,编写多个配置类。用于导入其他配置类

java 复制代码
package com.qcby.demo4;
import org.springframework.context.annotation.Configuration;

/**
 * 新的配置类
 *
 */
@Configuration      // 声明配置类
public class SpringConfig2 {
}

// 声明当前类是配置类
@Configuration
// 扫描指定的包结构
@ComponentScan(value = "com.qcby.demo4")
// @ComponentScan(value = {"com.qcby.demo4","com.qcby.demo3"})
// 引入新的配置类
@Import(value = {SpringConfig2.class})
public class SpringConfig {
}

@Bean注解 只能写在方法上,表明使用此方法创建一个对象,对象创建完成保存到IOC容器中

java 复制代码
package com.qcby.demo4;
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.context.annotation.Import;
import javax.sql.DataSource;

/**
 *
 * Spring的配置类,替换掉applicationContext.xml
 *
 */
// 声明当前类是配置类
@Configuration
// 扫描指定的包结构
@ComponentScan(value = "com.qcby.demo4")
// @ComponentScan(value = {"com.qcby.demo4","com.qcby.demo3"})
// 引入新的配置类
@Import(value = {SpringConfig2.class})
public class SpringConfig {
    /**
     * 创建连接池对象,返回对象,把该方法创建后的对象存入到连接池中,使用@Bean注解解决
         <!--配置连接池对象-->
         <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
             <property name="driverClassName" value="com.mysql.jdbc.Driver" />
             <property name="url" value="jdbc:mysql:///spring_db" />
             <property name="username" value="root" />
             <property name="password" value="123456" />
         </bean>
     *
     * @return
     */
    @Bean(name="dataSource")
    public DataSource createDataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///spring_db");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }
}​

8、Spring框架整合JUnit单元测试

① Spring框架整合JUnit单元测试

每次进行单元测试的时候,都需要编写创建工厂,加载配置文件等代码,比较繁琐。Spring提供了整合Junit单元测试的技术,可以简化测试开发。

必须先有Junit单元测试的环境,也就是说已经导入Junit单元测试的jar包。咱们已经导入过了。使用的是4.12版本

再导入spring-test的坐标依赖

java 复制代码
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.0.2.RELEASE</version>
    <scope>test</scope>
</dependency>

编写类和方法,把该类交给IOC容器进行管理

java 复制代码
package com.qcby.demo5;

public class User {
    public void sayHello(){
        System.out.println("Hello....");
    }
}

编写配置文件applicationContext_test.xml

java 复制代码
<?xml version="1.0"
encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
                    http://www.springframework.org/schema/beans
                    http://www.springframework.org/schema/beans/spring-beans.xsd">
    
​<!--整合单元测试-->
<bean id="user" class="com.qcby.demo5.User"/>

​</beans>

编写测试代码

java 复制代码
package com.qcby.test;
import com.qcby.demo5.User;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
  * Spring整合Junit单元测试
 *
 */
@RunWith(value = SpringJUnit4ClassRunner.class)     // 运行单元测试
@ContextConfiguration(value = "classpath:applicationContext_test.xml")   // 加载类路径下的配置文件
public class Demo5 {
    // 测试哪一个对象,把该对象注入进来,在测试环境下,可以使用注解的方式注入测试的对象
    // 按类型自动注入
    @Autowired
    private User user;

    @Test
    public void run1(){
        // 创建工厂,加载配置文件......
        // 调用对象的方法
        user.sayHello();
    }
}

②Spring整合单元测试(纯注解方式)

编写类和方法

java 复制代码
package com.qcby.demo6;
import org.springframework.stereotype.Component;

​@Component
public class Customer {
    public void save(){
        System.out.println("保存客户...");
    }
}

编写配置类

java 复制代码
package com.qcby.demo6;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

/**
  * Spring整合Junit配置类
 */
// 声明
@Configuration
// 扫描包结构
@ComponentScan(value = "com.qcby.demo6")
public class SpringConfig6 {
}

编写测试方法

java 复制代码
package com.qcby.test;
import com.qcby.demo6.Customer;
import com.qcby.demo6.SpringConfig6;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

/**
 * Spring整合Junit 注解的方式测试
 */
@RunWith(SpringJUnit4ClassRunner.class)
// 加载配置类
@ContextConfiguration(classes = SpringConfig6.class)
public class Demo6 {
​    // 按类型注入
    @Autowired
    private Customer customer;
    /**
     * 测试
     */
    @Test
    public void run(){
        customer.save();
    }
}
相关推荐
风_流沙3 分钟前
java 对ElasticSearch数据库操作封装工具类(对你是否适用嘞)
java·数据库·elasticsearch
颜淡慕潇26 分钟前
【K8S问题系列 |19 】如何解决 Pod 无法挂载 PVC问题
后端·云原生·容器·kubernetes
ProtonBase32 分钟前
如何从 0 到 1 ,打造全新一代分布式数据架构
java·网络·数据库·数据仓库·分布式·云原生·架构
乐之者v39 分钟前
leetCode43.字符串相乘
java·数据结构·算法
suweijie7684 小时前
SpringCloudAlibaba | Sentinel从基础到进阶
java·大数据·sentinel
公贵买其鹿5 小时前
List深拷贝后,数据还是被串改
java
向前看-8 小时前
验证码机制
前端·后端
xlsw_8 小时前
java全栈day20--Web后端实战(Mybatis基础2)
java·开发语言·mybatis
神仙别闹9 小时前
基于java的改良版超级玛丽小游戏
java
黄油饼卷咖喱鸡就味增汤拌孜然羊肉炒饭9 小时前
SpringBoot如何实现缓存预热?
java·spring boot·spring·缓存·程序员