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容器会在运行时自动将这些依赖关系注入到对象中。这种方式使得对象的创建和依赖关系的配置更加灵活和可维护。

2. 面向切面编程(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>

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

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的配置文件,名称是可以任意的,但是一般都会使用默认名称。

<?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>

编写测试方法

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对象的三种方式

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

<bean id="us" class="com.qcby.service.UserServiceImpl" />

②静态工厂实例化方式

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" />        

③动态工厂实例化方式

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方法,编写配置文件完成属性值的注入

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>

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

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

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等的注入

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的目录下又多创建了一个配置文件,现在是两个核心的配置文件,那么加载这两个配置文件的方式有两种!

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

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

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

① Spring框架开发方式

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

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

    <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>

创建数据库,创建表结构

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的类

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的接口和实现类

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;
   } 
 }

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();
   }
}

编写配置文件

<?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>

编程测试程序

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注解的方式依赖没有变化

编写接口和实现类

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注解

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

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

<?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>

编写测试方法

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的垃圾回收机制控制的

具体的代码如下

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纯注解的方式

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

编写实体类

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配置文件

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 {
}

测试方法的编写

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的配置文件可以分成多个配置的,编写多个配置类。用于导入其他配置类

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容器中

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的坐标依赖

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.0.2.RELEASE</version>
    <scope>test</scope>
</dependency>

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

package com.qcby.demo5;

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

编写配置文件applicationContext_test.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
                    http://www.springframework.org/schema/beans/spring-beans.xsd">
    
​<!--整合单元测试-->
<bean id="user" class="com.qcby.demo5.User"/>

​</beans>

编写测试代码

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整合单元测试(纯注解方式)

编写类和方法

package com.qcby.demo6;
import org.springframework.stereotype.Component;

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

编写配置类

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 {
}

编写测试方法

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();
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/358815.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

[每日一题] 01.30

文章目录 数列求和质数口袋奇怪数求和 数列求和 n int(input()) print(sum([i for i in range(1,n 1)]))质数口袋 n int(input()) i 2 sum 0 count 0 while n - i > sum:flag Truefor j in range(2,i): # 判断i是否为素数if i % j 0:flag Falsebreakif flag:sum i…

【LLM多模态】Cogview3、DALL-E3、CogVLM、CogVideo模型

note 文章目录 noteVisualGLM-6B模型图生文&#xff1a;CogVLM-17B模型1. 模型架构2. 模型效果 文生图&#xff1a;CogView3模型DALL-E3模型CogVideo模型网易伏羲-丹青模型Reference VisualGLM-6B模型 VisualGLM 是一个依赖于具体语言模型的多模态模型&#xff0c;而CogVLM则是…

BL808学习日志-3-DPI-RGB屏幕使用-LVGL D0

一、DPI-RGB驱动 BL808的手册上显示是支持RGB565屏幕显示输出的&#xff0c;但是一直没找到网上的使用例程。且官方的SDK显示也是能够使用的&#xff0c;只是缺少了驱动。这一部分驱动在SIPEED的SDK中已经内置了&#xff0c;今天就是简单的点亮一个800*480 RGB565的屏幕。 二、…

如何优化博客的内容和用户体验

在当今数字时代&#xff0c;博客成为了分享知识、展示个人专业能力和吸引读者的重要工具。然而&#xff0c;随着越来越多的博客涌现&#xff0c;如何优化博客的内容和用户体验成为了一个关键的问题。本文将为你提供一些有效的技巧&#xff0c;帮助你优化博客的内容和提升用户体…

开启公网即访问:GpuMall平台的云服务解决方案

在人工智能的黄金时代&#xff0c;数据科学家和AI工程师正面临着一个共同的挑战&#xff1a;如何快速、有效地将开发中的服务部署至公网&#xff0c;以应对日益增长的计算和访问需求。GpuMall智算云平台提供了一个全面的解决方案&#xff0c;让这一切变得简单。本文将深入探讨G…

【C++】C++入门—— 引用

引用 1 前情提要2 概念剖析3 引用特性4 常引用5 使用场景5.1做参数5.2 做返回值 6 传值 传引用的效率比较7 引用与指针的差异Thanks♪(&#xff65;ω&#xff65;)&#xff89;谢谢阅读下一篇文章见 1 前情提要 在C语言中&#xff0c;我们往往会遇见复杂的指针&#xff08;如…

python 写入csv文件 内容乱码

问题 python 写入csv文件 内容乱码 详细问题 笔者核心代码 import csv # 将数据写入 CSV 文件 csv_file_path "soil_data.csv" header ["经度", "纬度", "土壤类型", "pH值"]with open(csv_file_path, mode"w&q…

java 社区资源管理系统Myeclipse开发mysql数据库web结构java编程计算机网页项目

一、源码特点 java Web社区资源管系统是一套完善的java web信息管理系统 &#xff0c;对理解JSP java编程开发语言有帮助&#xff0c;系统具有完整的源代码和数据库&#xff0c;系统主要采用B/S模式开发。开发环境为TOMCAT7.0,Myeclipse8.5开发&#xff0c;数据库为Mysql5.…

vue3封装el-pagination分页组件

1、效果如图&#xff1a; 2、分页组件代码&#xff1a; <template><div class"paging"><el-config-provider :locale"zhCn"><el-paginationv-model:current-page"page.currentPage"v-model:page-size"page.pageSize…

如何更新github上fork的项目(需要一定git基础)

如何更新Fork的项目(需要一定git基础) 前言&#xff1a;本文记录一下自己在github上fork了大佬的开源博客项目https://github.com/tangly1024/NotionNext&#xff0c;如何使用git克隆以及自定义开发和同步合并原项目更新迭代内容的的步骤 如何更新fork的项目(进阶版) 首先你…

DML的原理:一篇文章让你豁然开朗

推荐阅读 给软件行业带来了春天——揭秘Spring究竟是何方神圣&#xff08;一&#xff09; 给软件行业带来了春天——揭秘Spring究竟是何方神圣&#xff08;二&#xff09; 文章目录 推荐阅读DML 数据操纵语言INSERT语句UPDATE语句DELETE语句SELECT语句 DML 数据操纵语言 DML是…

深入了解Yum:Linux系统的软件包管理利器

目录 软件包 软件包的来源 关于yum yum是什么 yum的相关操作 介绍rzsz rz&#xff08;从Windows本地传到Linux服务器&#xff09; sz&#xff08;从Linux服务器传到Windows本地&#xff09; 注意事项 查看软件包 安装软件 卸载软件 yum的本地配置 为什么要进行配置…

UDP/TCP协议特点

1.前置知识 定义应用层协议 1.确定客户端和服务端要传递哪些信息 2.约定传输格式 网络上传输的一般是二进制数据/字符串 结构化数据转二进制/字符串 称为序列化 反之称之为反序列化 下面就是传输层了 在TCP/IP协议中,我们以 目的端口,目的IP 源端口 源IP 协议号这样一个五…

蓝桥杯-常用STL(一)

常用STL &#x1f388;1.动态数组&#x1f388;2.vector的基础使用&#x1f52d;2.1引入库&#x1f52d;2.2构造一个动态数组&#x1f52d;2.3插入元素&#x1f52d;2.4获取长度并且访问元素&#x1f52d;2.5修改元素&#x1f52d;2.6删除元素&#x1f52d;2.7清空 &#x1f38…

Redis核心技术与实战【学习笔记】 - 8.Redis 时间序列数据处理

在做 web 产品是&#xff0c;都会有这么一个需求&#xff1a; 记录用户在网站或 APP 上的点击行为数据&#xff0c;来分析用户行为。这里的数据一般包括用户 ID、行为类型&#xff08;如浏览、登录、下单等&#xff09;、行为发生的时间戳。 userID, type, timeStamp 与之类似&…

Prometheus的pod部署

创建命名空间和账户以及集群账户 kubectl create ns monitor-sa kubectl create serviceaccount monitor -n monitor-sa kubectl create clusterrolebinding monitor-clusterrolebinding -n monitor-sa --clusterrolecluster-admin --serviceaccountmonitor-sa:monitor 创建…

视网膜长尾数据

视网膜长尾数据 问题&#xff1a;视网膜疾病分类&#xff0c;解法&#xff1a;深度学习模型问题&#xff1a;数据复杂性处理&#xff0c;解法&#xff1a;多任务框架&#xff08;同时处理多种疾病&#xff09;和少量样本学习&#xff08;提高对罕见疾病的识别&#xff09;问题&…

找不到MSVCR120.dll,缺失MSVCR120.dll的多种解决方法

当计算机系统在运行过程中无法找到MSVCR120.dll这个特定的动态链接库文件时&#xff0c;可能会引发一系列问题和异常情况。首先&#xff0c;这可能导致某些应用程序无法正常启动或运行&#xff0c;因为MSVCR120.dll是许多基于Microsoft Visual C编译的应用程序所必需的核心组件…

Inventor 2024下载安装教程,免费使用,附安装包和工具,流程简单,小白也能轻松搞定

前言 Inventor是一款专业的三维可视化实体建模软件&#xff0c;Inventor.主要用于各类二维机械制图、三维制图的设计和开发等操作&#xff0c;可以广泛地应用于零件设计、钣金设计、装配设计等领域。 准备工作 1、Win7及以上系统 2、提前准备好 Inventor 2024 安装包 没有…

开源项目TARZAN-NAV | 基于springboot的现代化导航网站系统

TARZAN-NAV 导航网站 一个基于 Spring Boot、MyBatis-Plus、h2database、ehcache、Docker、websocket等技术栈实现的导航网站系统&#xff0c;采用主流的互联网技术架构、全新的UI设计、支持一键源码部署&#xff0c;拥有完整的仪表板、导航管理&#xff0c;用户管理、评论管理…