Spring-day02

Spring-day02

01_开启Spring注解

目标

  • 能够设置Spring的注解扫描

路径

  1. 注解开发的意义
  2. 在配置文件中开启Spring注解扫描

注解开发的意义

在Spring中除了可以使用xml配置IoC外,还可以使用注解配置IoC

  • 注解配置相对xml方式会比较简洁,但是阅读性也会差一些

Spring启动时使用注解的形式替代xml配置,将繁杂的spring配置文件从工程中彻底消除掉,简化书写

1591023265469

注解配置的弊端:

  • 注解的配置需要基于源代码
    • 为了达成注解驱动的目的,可能会将原先很简单的书写,变的更加复杂

在配置文件中开启Spring注解扫描

在Spring中要使用注解配置,要启动注解扫描:

  • 根据指定的包名,加载类中配置的注解项
<context:component-scan base-package="packageName"/>

说明:

  • 在进行包扫描时,会对配置的包及其子包中所有文件进行扫描

  • 扫描过程是以文件夹递归迭代的形式进行的

  • 扫描过程仅读取合法的java文件

  • 扫描时仅读取spring可识别的注解

  • 扫描结束后会将可识别的有效注解转化为spring对应的资源加入IoC容器

注意:

  • 无论是注解格式还是XML配置格式,最终都是将资源加载到IoC容器中,差别仅仅是数据读取方式不同

    • 从加载效率上来说注解优于XML配置文件

02_IoC的注解配置-装配bean

目标

  • 能够使用@Component注解装配bean

路径

  1. @Component注解介绍
  2. 使用@Component注解装配bean

@Component注解介绍

在Spring中使用@Component注解,设置类为spring管理的bean

@Component   //相当于在xml中配置:<bean id="" class="">
public class ClassName{
}

@Component注解中的属性:

  • value : 指定bean的id。如果不指定value属性,默认bean的id是当前类的类名(首字母小写)。
@Component("service") //相当于在xml中配置:<bean id="service" class="包.UserServiceImpl">
public class UserServiceImpl implements UserService{
}

使用@Component注解装配bean

在Spring中使用注解的步骤:

  1. 开启spring注解扫描
  2. 在类上添加@Component注解

代码示例:

  • 配置文件
<?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
        http://www.springframework.org/schema/context/spring-context.xsd">


    <!-- 开启spring注解扫描
         spring扫描指定包下的类,加载配置了注解的类
    -->
    <context:component-scan base-package="com.itheima"/>

</beans>
  • 业务层
//接口
public interface IUserService {
    public void saveUser(User user);
}

//实现类
@Component("userService")
public class UserServiceImpl implements IUserService {
    @Override
    public void saveUser(User user) {
        System.out.println("UserSerive => saveUser方法");
    }
}
  • 测试类
public class UserServiceTest {

    private IUserService userService;//业务对象

    @Before
    public void initUserService() {
        //加载配置文件初始化容器
        ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");

        //从容器中获取对象
        userService = (IUserService) cxt.getBean("userService");
    }

    
    @Test
    public void testSaveUser() {
        //创建User对象
        User user = new User("黑马","123123");

        userService.saveUser(user);
    }
}

03_IoC的注解配置-衍生注解

目标

  • 能够使用衍生注解装配bean

路径

  1. 衍生注解介绍
  2. 使用衍生注解装配bean

衍生注解介绍

在@Component注解下,衍生了@Controller、@Service 、@Repository三个注解。功能同等于@Component

  • 衍生注解提供了更加明确的语义
    • @Controller:一般用于表现层的注解
    • @Service:一般用于业务层的注解
    • @Repository:一般用于持久层的注解

使用衍生注解装配bean

使用衍生注解完成bean的装配:

1、 使用@Service注解装配service的实现类

2、 使用@Respository注解装配dao的实现类

代码示例:

  • 配置文件
<?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
        http://www.springframework.org/schema/context/spring-context.xsd">


    <!-- 开启spring注解扫描
         spring扫描指定包下的类,加载配置了注解的类
    -->
    <context:component-scan base-package="com.itheima"/>

</beans>
  • Dao层(持久层)
//接口
public interface IUserDao {
    public void addUser(User user);
}


//实现类
@Repository("userDao")
public class UserDaoImpl implements IUserDao{
    /**
     * 添加用户
     * @param user
     */
    @Override
    public void addUser(User user) {
        System.out.println("UserDao => addUser方法");
    }
}
  • 业务层
//接口
public interface IUserService {
    public void saveUser(User user);
}

//实现类
@Service("userService")
public class UserServiceImpl implements IUserService {
    @Override
    public void saveUser(User user) {
        System.out.println("UserSerive => saveUser方法");
    }
}
  • 测试类
//测试dao层
public class UserDaoTest {
    private IUserDao userDao;

    @Before
    public void initUserService() {
        //加载配置文件初始化容器
        ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");

        //从容器中获取对象
        userDao = (IUserDao) cxt.getBean("userDao");
    }

    @Test
    public void testAddUser() {
        //创建User对象
        User user = new User("黑马", "123123");

        userDao.addUser(user);
    }
}



//测试业务层
public class UserServiceTest {

    private IUserService userService;

    @Before
    public void initUserService() {
        //加载配置文件初始化容器
        ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");

        //从容器中获取对象
        userService = (IUserService) cxt.getBean("userService");
    }

    @Test
    public void testSaveUser() {
        //创建User对象
        User user = new User("黑马","123123");

        userService.saveUser(user);
    }
}
虽然从spring容器中单独获取service的实现类和dao的实现类都没有问题。
但是当在service实现类中加入dao对象后时,发现会报空指针异常

image-20220423141809291

原因是service的实现类中调用了dao的实现类,但是dao的实现类对象并没有被注入到service的实现类中,因此造成了空指针异常。
原因分析:我们仅仅使用注解装配了bean,但是并没有将dao注入到service中。
解决方案:使用注解注入

04_IoC的注解配置-属性注入1

目标

  • 能够使用@Autowired或@Qualifier实现引用类型属性注入

路径

  1. @Autowired注解介绍
  2. 使用@Autowired向业务类中注入dao对象
  3. @Qualifier注解介绍

@Autowired注解介绍

@Autowired注解:

public class ClassName{
    @Autowired
    private 引用类型 对象名;
}
  • 作用:按照类型注入引用类型对象
    • 当容器中只有一个类型匹配的对象时直接注入
    • 当有多个类型匹配的对象时,使用要注入的对象的变量名称作为bean的id,在spring容器查找,找到了也可以注入成功,找不到就报错。
  • 细节:当使用注解注入属性时,可以省略setter方法

image-20220512103831305

使用@Autowired向业务类中注入dao对象

代码示例:

  • 业务层
@Service("userService")
public class UserServiceImpl implements IUserService {
    @Autowired  //自动按照类型注入
    private IUserDao userDao;//dao层对象

    @Override
    public void saveUser(User user) {
        System.out.println("UserSerive => saveUser方法");
        userDao.addUser(user);
    }
}
  • 测试类
public class UserServiceTest {
    private IUserService userService;

    @Before
    public void initUserService() {
        //加载配置文件初始化容器
        ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");

        //从容器中获取对象
        userService = (IUserService) cxt.getBean("userService");
    }

    @Test
    public void testSaveUser() {
        //创建User对象
        User user = new User("黑马","123123");

        userService.saveUser(user);
    }
}
//输出结果:
UserSerive => saveUser方法
UserDao => addUser方法
@Autowired注解的属性: 
     required (通常不用书写)[了解即可]
     取值:
         true: 此对象必须注入成功,若不成功则报错 (默认值)
         false: 可以注入不成功,此对象为null

@Qualifier注解介绍

@Qualifier注解:

public class ClassName{
    @Autowired
    @Qualifier("beanId")
    private 引用类型 对象名;
}
  • 作用:在自动按照类型注入(@Autowired)的基础之上,再按照bean的id注入

  • 应用场景:

    在使用@Autowired注入,当有多个类型匹配的对象时:
    按照@Qualifier("beanId")注解指定beanId进行注入
    
  • 属性: value , 指定bean的id

  • 注意事项:@Qualifier注解不能独立使用,必须和@Autowired一起使用

代码示例:

  • Dao层 (有多个类型相同的Dao对象)
//第1个:IUserDao
@Repository("userDao")
public class UserDaoImpl implements IUserDao {
    @Override
    public void addUser(User user) {
        System.out.println("UserDao => addUser方法");
    }
}


//第2个:IUserDao
@Repository("userDao2")
public class UserDaoImpl2 implements IUserDao {
    @Override
    public void addUser(User user) {
        System.out.println("UserDao2 => addUser方法");
    }
}
  • 业务层
@Service("userService")
public class UserServiceImpl implements IUserService {
    @Autowired
    @Qualifier("userDao2") //从容器中获取名为"userDao2"的对象注入
    private IUserDao userDao;

    @Override
    public void saveUser(User user) {
        System.out.println("UserSerive => saveUser方法");
        userDao.addUser(user);
    }
}

05_IoC的注解配置-属性注入2

目标

  • 能够使用@Value实现非引用类型属性注入

路径

  1. @Value注解介绍
  2. 使用@Value向基本类型或String类型属性注入数据

@Value注解介绍

@Value注解:

public class ClassName{
    @Value("100")
    private int num;
    @Value("黑马")
    private String name;
}
  • 说明:

    • value值仅支持基本数据、String类型、包装类类型

    • value值支持读取properties文件中的属性值

    • value值支持SpringEL表达式

    • @value注解如果添加在属性上方,可以省略setter方法

  • 相关属性

    • value(默认):定义对应的属性值

使用@Value向基本类型或String类型属性注入数据

代码示例:

  • 业务层
@Service("userService2")
public class UserServiceImpl2 implements IUserService {
    @Value("1000")
    private int num; //基本类型
    @Value("黑马")
    private String name; //String类型
    @Value("20")
    private Integer age; //Integer类型(包装类)

    @Autowired
    private IUserDao userDao;

    @Override
    public void saveUser(User user) {
        System.out.println("UserSerive2 => saveUser方法");

        System.out.println("int类型:"+num);
        System.out.println("String类型:"+name);
        System.out.println("包装类类型:"+age);

        userDao.addUser(user);
    }
}
  • 测试类
public class UserServiceTest {
    private IUserService userService;

    @Before
    public void initUserService() {
        //加载配置文件初始化容器
        ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");

        //从容器中获取对象
        userService = (IUserService) cxt.getBean("userService2");
    }

    @Test
    public void testSaveUser() {
        //创建User对象
        User user = new User("黑马","123123");    
        userService.saveUser(user);
    }
}
//输出结果:
UserSerive2 => saveUser方法
int类型:1000
String类型:黑马
包装类类型:20
UserDao => addUser方法

06_IoC的注解配置-加载properties文件

目标

  • 能够使用@PropertySource加载properties文件

路径

  1. @PropertySource注解介绍
  2. 使用@PropertySource加载properties文件

@PropertySource注解介绍

@PropertySource注解:

@PropertySource(value = "文件名.properties")
public class ClassName {
    @Value("${properties文件中的属性名}")
    private String attributeName;
}
  • 作用:加载外部properties配置文件
  • 属性:value , 设置加载的properties文件名

使用@PropertySource加载properties文件

代码示例:

  • properties文件
name=heima
num=10
  • 业务层
@Service("userService2")
@PropertySource(value = "data.properties") //引入外部properties配置文件
public class UserServiceImpl2 implements IUserService {
    @Value("${num}") //获取配置文件中的数据
    private int num;  
    @Value("${name}")
    private String name; 
    @Value("${age}")
    private Integer age; 

    @Autowired
    private IUserDao userDao;

    @Override
    public void saveUser(User user) {
        System.out.println("UserSerive2 => saveUser方法");

        System.out.println("int类型:"+num);
        System.out.println("String类型:"+name);
        System.out.println("包装类类型:"+age);

        userDao.addUser(user);
    }
}
  • 测试类
public class UserServiceTest {
    private IUserService userService;

    @Before
    public void initUserService() {
        //加载配置文件初始化容器
        ApplicationContext cxt = new ClassPathXmlApplicationContext("applicationContext.xml");

        //从容器中获取对象
        userService = (IUserService) cxt.getBean("userService2");
    }

    @Test
    public void testSaveUser() {
        //创建User对象
        User user = new User("黑马","123123");

        userService.saveUser(user);
    }
}
//输出结果:
UserSerive2 => saveUser方法
int类型:10
String类型:heima
包装类类型:20
UserDao => addUser方法

小结

从外部资源文件中获取数据:

  1. 使用:@PropertySource注解,加载外部配置文件
  2. 使用:@Value注解+SpringEL表达式,获取配置文件中的数据

07_IoC的注解配置-纯注解开发

目标

  • 能够使用Spring纯注解方式编写程序

路径

  1. @Configuration注解介绍
  2. @ComponentScan注解介绍
  3. 使用纯注解形式开发

取消spring的xml配置文件,使用纯注解开发模式:

  1. 指定配置类,代替xml配置文件
  2. 在配置类中指定要扫描的包
  3. 使用AnnotationConfigApplicationContext类代替ClassPathXmlApplicationContext类

@Configuration注解介绍

@Configuration注解

@Configuration
public class SpringConfig{
}

作用:指定当前类是一个spring配置类,当创建容器时会从该类上加载注解

  • 简单来讲:就是替换掉spring的xml配置文件(不在使用applicationContext.xml配置文件了)

面临的问题:使用配置类代替了XML配置文件了,但是如何配置创建容器时要扫描的包呢?

  • 使用:@ComponentScan注解

@ComponentScan注解介绍

@ComponentScan注解:

@Configuration
@ComponentScan("包名路径")
public class SpringConfig{
}
  • 作用:用于指定spring在初始化容器时要扫描的包

    • 和xml配置文件中的功能一样

      <context:component-scan base-package="包名路径"/>
      
  • 属性: value , 用于指定要扫描的包。和标签中的base-Package属性作用一样。

使用纯注解形式开发

纯注解方式开发:使用AnnotationConfigApplicationContext类加载注解配置

image-20220417122831926

获取容器时要使用:AnnotationApplicationContext(有@Configuration注解的类.class)

ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

代码示例:

  • 配置类
@Configuration  //当前类是Spring配置类
@ComponentScan("com.itheima")//指定扫描的包
@PropertySource(value = "data.properties")//加载外部资源文件
public class SpringConfig {
}
  • 业务类
@Service("userService2")
//@PropertySource(value = "data.properties") //可以删除(配置类中已加载了外部配置文件)
public class UserServiceImpl2 implements IUserService {
    @Value("${num}")
    private int num; //基本类型
    @Value("${name}")
    private String name; //String类型
    @Value("${age}")
    private Integer age; //Integer类型(包装类)

    @Autowired
    private IUserDao userDao;

    @Override
    public void saveUser(User user) {
        System.out.println("UserSerive2 => saveUser方法");

        System.out.println("int类型:"+num);
        System.out.println("String类型:"+name);
        System.out.println("包装类类型:"+age);

        userDao.addUser(user);
    }
}
  • 测试类
public class UserServiceTest2 {
    private IUserService userService;

    @Before
    public void initUserService() {
        //加载配置类初始化容器 (不使用XML配置文件了)
       ApplicationContext cxt = new AnnotationConfigApplicationContext(SpringConfig.class); 

        //从容器中获取对象
        userService = (IUserService) cxt.getBean("userService2");
    }

    @Test
    public void testSaveUser() {
        //创建User对象
        User user = new User("黑马","123123");
        userService.saveUser(user);
    }
}

小结

使用纯注解形式开发Spring的步骤:

  1. 创建Spring配置类(代替xml配置文件)
    • 使用:@Configurable注解表示当前类为配置类
  2. 在Spring配置类上,指定要扫描的包路径
    • 使用:@ComponentScan注解指定扫描的包
  3. 使用AnnotationConfigApplicationContext创建Spring容器

08_IoC的注解配置-加载第三方资源

目标

  • 能够使用@Bean注解装配bean

路径

  1. @Bean注解介绍
  2. 使用@Bean加载第三方资源
  3. 第三方bean配置与管理

在XML配置文件中,可以把第三方框架(例:Druid)中的类,配置到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
        http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 配置Druid中的类,作为Spring容器中的一个资源 -->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/db1"></property>
        <property name="username" value="root"></property>
        <property name="password" value="itheima"></property>
    </bean>
</beans>
  • 通过bean标签的id值,就可以获取到第三方框架中类的对象

问题:当使用纯注解开发模式后,就取消了XML配置文件,如果要从spring容器中获取第三框架中的类,怎么办?

答案:第三方框架的bean是无法在其源码上进行修改,可以使用@Bean实现第三方bean的引入

@Bean注解介绍

@Bean注解:

@Component
public class ClassName{
    @Bean("名字")
    public 返回值类型 方法名(){
        return 返回值;    
    }
}
  • 作用:设置方法的返回值作为spring管理的bean(将方法的返回值作为一个bean,并且放入spring容器)
  • 属性:value , 定义bean的访问id

说明:

  • @Bean注解用于替代XML配置中的静态工厂与实例工厂创建bean(不区分方法是否为静态或非静态)
  • @Bean所在的类必须被spring扫描加载,否则该注解无法生效

使用@Bean加载第三方资源

代码示例:

  • 第三方资源
@Component  //@Bean所在的类必须被spring扫描加载,否则该注解无法生效
public class MyDataSource {

    @Bean("druidDataSource")  //bean的id名(spring容器中资源的名字)
    public DataSource createDruidDataSource(){
        //创建第三方资源对象
        DruidDataSource druidDataSource = new DruidDataSource();
        //设置参数
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/db1");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("itheima");
        //返回对象
        return druidDataSource;
    }
}
  • Dao层
@Repository("userDao")
public class UserDaoImpl implements IUserDao {
    @Autowired
    @Qualifier("druidDataSource") //指定bean的名字
    private DataSource dataSource;

    /**
     * 添加用户
     * @param user
     */
    @Override
    public void addUser(User user) {
        System.out.println("UserDao => addUser方法");
        
        try {
            System.out.println("数据库连接状态:"+dataSource.getConnection().isClosed());
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }
}
  • 测试类
public class UserDaoTest2 {
    private IUserDao userDao;

    @Before
    public void initUserService() {
        //加载配置类初始化容器
        ApplicationContext cxt = new AnnotationConfigApplicationContext(SpringConfig.class);

        //从容器中获取对象
        userDao = (IUserDao) cxt.getBean("userDao");
    }

    @Test
    public void testAddUser() {
        //创建User对象
        User user = new User("黑马", "123123");

        userDao.addUser(user);
    }
}

//输出结果:
UserDao => addUser方法
数据库连接是否关闭:false

第三方bean配置与管理

以上程序代码中,使用@Component注解,保证第三方框架中的类可以被spring扫描加载

除了这种方式外,还可以使用@Import注解,导入第三方bean作为spring控制的资源

@Import注解:

@Import(MyDataSource.class)
public class ClassName {
}

说明:

  • @Import注解在同一个类上,仅允许添加一次,如果需要导入多个,使用数组的形式进行设定

    @Import(value = {MyDataSource.class, MyDS.class , .... })//按照顺序加载
    //@Import(...)//同一个类上,不允许出现2次Import
    public class ClassName {
    }
    
  • 在被导入的类中可以继续使用@Import导入其他资源(了解)

  • @Bean所在的类可以使用导入的形式进入spring容器,无需声明为bean

代码示例:

  • 配置类
@Configurable  //当前类是Spring配置类
@ComponentScan("com.itheima")//指定扫描的包
@PropertySource(value = "data.properties")//加载外部资源文件
@Import(MyDataSource.class)  //导入MyDataSource类
public class SpringConfig {
}
  • 第三方资源Bean
//@Component   //可以删除  (在配置类中导入了MyDataSource类)
public class MyDataSource {

    @Bean("druidDataSource")  //bean的id名(spring容器中资源的名字)
    public DataSource createDruidDataSource(){
        //创建第三方资源对象
        DruidDataSource druidDataSource = new DruidDataSource();
        //设置参数
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/db1");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("itheima");
        //返回对象
        return druidDataSource;
    }
}

另一种方式:直接在SpringConfig配置类中添加第三方Bean资源

@Configurable  //当前类是Spring配置类
@ComponentScan("com.itheima")//指定扫描的包
@PropertySource(value = "data.properties")//加载外部资源文件
public class SpringConfig {
    
    @Bean("druidDataSource")  //bean的id名(spring容器中资源的名字)
    public DataSource createDruidDataSource(){
        //创建第三方资源对象
        DruidDataSource druidDataSource = new DruidDataSource();
        //设置参数
        druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/db1");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("itheima");
        //返回对象
        return druidDataSource;
    }
}

09_IoC的注解配置-bean作用域

目标

  • 了解@Scope设置bean作用域的方式

路径

  1. @Scope注解介绍
  2. 使用@Scope设置Bean作用域

@Scope注解介绍

@Scope注解:

@Component
@Scope
public class ClassName{
}
  • 作用:设置该类作为bean对应的scope属性
  • 属性:value ,定义bean的作用域。(默认为singleton)

使用@Scope设置Bean作用域

代码示例:

  • Dao层
@Repository("userDao2")
@Scope("singleton")    //单例
//@Scope("prototype")  //非单例
public class UserDaoImpl2 implements IUserDao {
    public UserDaoImpl2(){
        System.out.println("UserDaoImpl2构造方法...");
    }
    /**
     * 添加用户
     * @param user
     */
    @Override
    public void addUser(User user) {
        System.out.println("UserDao2 => addUser方法");
    }
}

  • 测试类
public class UserDaoTest3 {
    @Test
    public void testBeanScope(){
        //加载配置类初始化容器
        ApplicationContext cxt = new AnnotationConfigApplicationContext(SpringConfig.class);

        //从容器中获取对象
        IUserDao userDao1 = (IUserDao) cxt.getBean("userDao2");
        IUserDao userDao2 = (IUserDao) cxt.getBean("userDao2");

        System.out.println(userDao1);
        System.out.println(userDao2);
    }
}

10_IoC的注解配置-bean生命周期

目标

  • 能够使用@PostConstruct、@PreDestroy设置初始化、销毁方法

路径

  1. 使用@PostConstruct、@PreDestroy设置初始化、销毁方法

@PostConstruct、@PreDestroy注解介绍

@PostConstruct注解:

@Component
public class ClassName{
    @PostConstruct
    public void init() {
        //初始化方法
    }
}

@PreDestroy注解:

@Component
public class ClassName{
    @PreDestroy
    public void destory() {
        //销毁方法
    }
}

代码示例:

@Repository("userDao2")
@Scope("singleton")
//@Scope("prototype")
public class UserDaoImpl2 implements IUserDao {
    public UserDaoImpl2(){
        System.out.println("UserDaoImpl2构造方法...");
    }

    @PostConstruct
    public void init(){
        System.out.println("UserDaoImpl2 => 初始化方法");
    }

    @PreDestroy
    public void destroy(){
        System.out.println("UserDaoImpl2 => 销毁方法");
    }

    /**
     * 添加用户
     * @param user
     */
    @Override
    public void addUser(User user) {
        System.out.println("UserDao2 => addUser方法");
    }
}
public class UserDaoTest3 {
    @Test
    public void testBeanScope(){
        //加载配置类初始化容器
        ApplicationContext cxt = new AnnotationConfigApplicationContext(SpringConfig.class);

        //从容器中获取对象
        IUserDao userDao1 = (IUserDao) cxt.getBean("userDao2");

        IUserDao userDao2 = (IUserDao) cxt.getBean("userDao2");

        System.out.println(userDao1);
        System.out.println(userDao2);
    }
}

11_Spring整合Mybatis

目标

  • 能够使用Spring整合Mybatis

路径

  1. 准备工作
  2. 使用Spring整合Mybatis
  3. 优化Spring和Mybatis的整合

我们之前介绍过,spring可以整合其他框架融合自己的体系, 下面我们一起来学习下使用spring整合mybatis

Spring整合Mybatis步骤:

  1. 创建基于mybatis的项目
  2. 使用spring的IoC改造mybatis

准备工作

前期准备工作:

  1. 数据库
  2. 构造maven项目
  3. 导入坐标 [Mybatis、Mysql、Druid、Spring]
  4. Pojo类
  5. Dao层
  6. Service层
  7. 配置文件
  8. 工具类:SqlSessionUtil
  • 数据库:
create database spring_db;
use spring_db;
## 表
create table account(
	id int primary key auto_increment,
	name varchar(20),
	money double	
);
## 测试数据
insert into account values(null,'jack',1000),(null,'rose',1000);
  • 构造maven项目:

image-20220423221719120

  • 导入坐标
<?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>com.itheima</groupId>
    <artifactId>spring_demo2-mybatis</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <!-- spring依赖 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.10.RELEASE</version>
        </dependency>
        <!--
           junit测试框架
        -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <!--
           mysql驱动
        -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.45</version>
        </dependency>
        <!--
            Druid
        -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.1</version>
        </dependency>
        <!--
            mybatis
        -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.3</version>
        </dependency>
    </dependencies>
</project>
  • Pojo类
public class Account {
    private Integer id;
    private String name;
    private Float 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 Float getMoney() {
        return money;
    }
    public void setMoney(Float money) {
        this.money = money;
    }
    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

  • Dao层
public interface AccountDao {
    @Insert("insert into account(name,money)values(#{name},#{money})")
    void saveAccount(Account account);

    @Delete("delete from account where id = #{id} ")
    void deleteAccountById(Integer id);

    @Update("update account set name = #{name} , money = #{money} where id = #{id} ")
    void updateAccount(Account account);

    @Select("select id,name,money from account")
    List<Account> findAll();

    @Select("select id,name,money from account where id = #{id} ")
    Account findById(Integer id);
}
  • Service层
//接口
public interface IAccountService {
    /**
     * 添加用户
     * @param account
     */
    public void saveAccount(Account account);

    /**
     * 修改用户
     * @param account
     */
    public void updateAccount(Account account);
    
    /**
     * 删除用户
     * @param id
     */
    public void deleteAccount(Integer id);
    
    /**
     * 根据id查询用户
     * @param id
     * @return
     */
    public Account findById(Integer id);

    /**
     * 查询所有用户
     * @return
     */
    public List<Account> findAll();
}



//实现类
public class AccountServiceImpl implements IAccountService {
    @Override
    public void saveAccount(Account account) {
        SqlSession session = SqlSessionUtil.getSession();
        AccountDao accountDao = session.getMapper(AccountDao.class);
        accountDao.saveAccount(account);
        session.close();
    }

    @Override
    public void updateAccount(Account account) {
        SqlSession session = SqlSessionUtil.getSession();
        AccountDao accountDao = session.getMapper(AccountDao.class);
        accountDao.updateAccount(account);
        session.close();
    }

    @Override
    public void deleteAccount(Integer id) {
        SqlSession session = SqlSessionUtil.getSession();
        AccountDao accountDao = session.getMapper(AccountDao.class);
        accountDao.deleteAccountById(id);
        session.close();
    }

    @Override
    public Account findById(Integer id) {
        SqlSession session = SqlSessionUtil.getSession();
        AccountDao accountDao = session.getMapper(AccountDao.class);
        Account account = accountDao.findById(id);
        session.close();
        return account;
    }

    @Override
    public List<Account> findAll() {
        SqlSession session = SqlSessionUtil.getSession();
        AccountDao accountDao = session.getMapper(AccountDao.class);
        List<Account> list = accountDao.findAll();
        session.close();
        return list;
    }
}
  • 配置文件

    • 数据库配置
    jdbc.driver=com.mysql.jdbc.Driver
    jdbc.url=jdbc:mysql://127.0.0.1:3306/spring_db
    jdbc.username=root
    jdbc.password=itheima
    
    • mybatis配置文件
    <?xml version="1.0" encoding="UTF-8"?>
    <!DOCTYPE configuration
            PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-config.dtd">
    <configuration>
        <!-- 引入外部资源文件 -->
        <properties resource="db.properties"/>
        <typeAliases>
            <package name="com.itheima.pojo"/>
        </typeAliases>
        <environments default="mysql">
            <environment id="mysql">
                <transactionManager type="JDBC"></transactionManager>
                <dataSource type="POOLED">
                    <property name="driver" value="${jdbc.driver}"></property>
                    <property name="url" value="${jdbc.url}"></property>
                    <property name="username" value="${jdbc.username}"></property>
                    <property name="password" value="${jdbc.password}"></property>
                </dataSource>
            </environment>
        </environments>
        <mappers>
            <!-- 指定扫描的包 -->
            <package name="com.itheima.dao"></package>
        </mappers>
    </configuration>
    
  • 工具类

public class SqlSessionUtil {
    private static SqlSessionFactory factory;

    static {
        //实例化工厂建造类
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        //读取核心配置文件
        try (InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml")) {
            //创建工厂对象
            factory = builder.build(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取会话对象
     * @return 会话对象 : 自动提交事务
     */
    public static SqlSession getSession() {
        return factory.openSession(true);
    }

    /**
     * 获取会话对象
     * @param isAutoCommit 是否自动提交事务
     */
    public static SqlSession getSession(boolean isAutoCommit) {
        return factory.openSession(isAutoCommit);
    }

    /**
     * 提交事务并关闭session
     * @param session
     */
    public static void commitAndClose(SqlSession session) {
        if (session != null) {
            session.commit();
            session.close();
        }
    }

    /**
     * 回滚事务并关闭session
     * @param session
     */
    public static void rollbackAndClose(SqlSession session) {
        if (session != null) {
            session.rollback();
            session.close();
        }
    }
}

使用Spring整合Mybatis

spring改造mybatis的步骤:

  1. 新增mybatis配置类:MybatisConfig
  2. 新增spring配置类:SpringConfig
  3. 修改AccountServiceImpl类
  • 新增mybatis配置类
//Mybatis配置类
public class MybatisConfig {
    //SqlSessionFactoryBuilder -> SqlSessionFactory -> SqlSession -> AccountDao
    
    //将SqlSessionFactory放入到ioc容器
    @Bean("factory")
    public SqlSessionFactory getFactory() throws IOException {
        SqlSessionFactoryBuilder builder = new SqlSessionFactoryBuilder();
        InputStream inputStream = Resources.getResourceAsStream("mybatis-config.xml");
        SqlSessionFactory factory = builder.build(inputStream);
        return factory;
    }

    //将SqlSession放到ioc容器中
    @Bean  //在方法上使用@Bean注解时:方法参数列表中声明的对象会自动从ioc容器中获取
    public SqlSession getSqlSession(SqlSessionFactory factory){
        SqlSession sqlSession = factory.openSession(true);
        return sqlSession;
    }

    //将accountDao放到ioc容器中
    @Bean("accountDao") //自动从ioc容器中获取SqlSession类型的bean对象
    public AccountDao getDao(SqlSession sqlSession){
        AccountDao accountDao = sqlSession.getMapper(AccountDao.class);
        return accountDao;
    }
}
  • 新增spring配置类
@Configuration
@ComponentScan("com.itheima")
@Import(MybatisConfig.class)
public class SpringConfig {
}
  • 修改AccountServiceImpl类
@Service("accountService")
public class AccountServiceImpl implements IAccountService {
    @Autowired  //自动注入
    private AccountDao accountDao;

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

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

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

    @Override
    public Account findById(Integer id) {
        Account account = accountDao.findById(id);
        return account;
    }

    @Override
    public List<Account> findAll() {
        List<Account> list = accountDao.findAll();
        return list;
    }
}

测试类:

public class AccountServiceTest {
    IAccountService accountService;

    @Before
    public void init(){
        //加载配置类初始化容器
        ApplicationContext cxt = new AnnotationConfigApplicationContext(SpringConfig.class);
        //从容器中获取对象
        accountService = (IAccountService) cxt.getBean("accountService");
    }

    @Test
    public void testFindAccountById(){
        Account account = accountService.findById(1);
        System.out.println(account);
    }
}

优化Spring和Mybatis的整合

优化spring和mybatis整合的步骤:

  1. 导入坐标
  2. 修改MybatisConfig类
  3. 修改SpringConfig类
  • 导入坐标
	<dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-jdbc</artifactId>
      <version>5.2.10.RELEASE</version>
    </dependency>

    <dependency>
      <groupId>org.mybatis</groupId>
      <artifactId>mybatis-spring</artifactId>
      <version>1.3.0</version>
    </dependency>
  • 修改MybatisConfig类
//Mybatis配置类
public class MybatisConfig {
    /*
        SqlSessionFactoryBean (mybatis的spring整合包提供的类)
        1. 底层会提供 SqlSessionFactory
        2. 当开发者需要注入dao层bean的,此SqlSessionFactory会自动提供
            还可以设置dao层的扫描
     */
    @Bean
    public SqlSessionFactoryBean getSqlSessionFactoryBean(DataSource ds){
        SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
        //设置pojo的包扫描
        //factoryBean.setTypeAliasesPackage("com.itheima.pojo");
        //设置连接池
        factoryBean.setDataSource(ds);

        return factoryBean;
    }

    //定义bean,返回MapperScannerConfigurer对象(mybatis的spring整合包提供的类)
    @Bean
    public MapperScannerConfigurer mapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        //设置dao层的接口扫描
        msc.setBasePackage("com.itheima.dao");
        return msc;
    }
}
  • 修改SpringConfig类
@Configuration
@ComponentScan("com.itheima")
@PropertySource("classpath:db.properties")
@Import(MybatisConfig.class)
public class SpringConfig {
    @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
    public DataSource getDataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(username);
        ds.setPassword(password);
        return ds;
    }
}

注意:连接池配置不能放在MybatisConfig类中(只有先创建好连接池对象,MybatisConfig类中才能使用)

  • 可以放在SpringConfig类中,或者另写一个配置类,但是要保证此配置类先于MybatisConfig加载

12_Spring整合Junit

目标

  • 能够使用Spring整合Junit

路径

  1. 测试类中存在的问题
  2. 解决问题的思路
  3. 涉及的知识点介绍
  4. 使用spring整合junit

测试类中存在的问题

在之前书写的测试类中,每个测试方法都有以下两行代码:

//加载配置初始化容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
或
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);    
//从容器中获取对象
IUserService userService = (IUserService)ac.getBean("userService"); 
  • 这两行代码如果不写的话:直接会提示空指针异常。(所以又不能轻易删掉)

解决问题的思路

解决思路:

  • 我们需要程序能自动帮我们创建容器。一旦程序能自动创建spring容器,我们就无须手动创建了,问题也就解决了。

我们都使用过junit,但是junit都无法知晓我们是否使用了spring框架,更不用说帮我们创建spring容器了。不过好在,junit给我们暴露了一个注解,可以让我们替换掉它的运行器。

在spring框架中提供了一个运行器,可以读取配置文件或注解配置类来创建容器。只需要告诉它配置类或配置文件在哪就行了。

涉及的知识点介绍

替换掉Junit的运行器:@RunWith

@RunWith(SpringJUnit4ClassRunner.class)//替换掉junit的运行器,换成可以初始化spring容器的运行器
public class 测试类{
}

加载SpringIoC容器:@ContextConfiguration

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {SpringConfig.class})//加载配置类
public class 测试类{
}
  • 属性:

    • class[] :用来指定配置类

    • value[] :用来指定xml配置文件的路径

      @ContextConfiguration(value = {"classpath:bean.xml"})
      

使用spring整合junit

使用spring整合junit的步骤:

  1. 导入坐标
  2. 在测试类上添加:@RunWith、@ContextConfiguration
<!-- 引入单元测试的jar包(需要在4.12及以上) --> 	
<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.12</version>
</dependency>

<!-- 导入Spring整合junit的jar包 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-test</artifactId>
    <version>5.2.10.RELEASE</version>
    <!-- 注意:要保证Spring体系下的jar包的版本号相同  -->
</dependency>

测试类:

@RunWith(SpringJUnit4ClassRunner.class) //SpringJUnit4ClassRunner替代junit原生执行器
@ContextConfiguration(classes= SpringConfig.class) //加载注解配置类
//@ContextConfiguration(value="classpath:applicationContext.xml") //加载xml配置文件
public class AccountTest {
    @Autowired   //自动装配依赖
    IAccountService accountService;
    
    @Test
    public void testFindAccountById(){
        Account ac = accountService.findById(1);
        System.out.println(ac);
    }
    
}
posted @   忘了鱼尾纱的猫  阅读(61)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 三行代码完成国际化适配,妙~啊~
· .NET Core 中如何实现缓存的预热?
  1. 1 刘哈哈与大先生 刘心&大鹏
  2. 2 我们打着光脚在风车下跑,手上的狗尾巴草摇啊摇 等一下就回家 / -艾兜
  3. 3 哎呦 毛不易
  4. 4 夜、萤火虫和你 AniFace
我们打着光脚在风车下跑,手上的狗尾巴草摇啊摇 - 等一下就回家 / -艾兜
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词:等一下就回家/艾兜

作曲:等一下就回家/艾兜

混音:裴济逸

编曲:HYPER MUSIC

风是从哪儿来手上的狗尾巴草摇的更剧烈

稻穗也晃起来我紧握着你的手把它拍成照片

我们俩转 就像大风车

早该逃离这我转转 把云卷散了

下个地方 风筝睡醒了

乘着它走吧 飘飘 等着大风车

像在画一幅油画

陶醉你的笑容

就沿着风车走吧

不用 猜忌 下个地点

让我忘记时间to the midnight

the sun came out 把所有染成金色的

风风风让它吹过来

至少年轻我还记得

oh 找一个地方落下

躺在谷仓里

和你讲着小话

什么风都吹不倒它

它就像是活的

知道哪是它的家

风是从哪儿来手上的狗尾巴草摇的更剧烈

稻穗也晃起来我紧握着你的手把它拍成照片

我们俩转 就像大风车

早该逃离这我转转 把云卷散了

下个地方 风筝睡醒了

乘着它走吧 飘飘 等着大风车

像在画一幅油画

陶醉你的笑容

就沿着风车走吧

不用 猜忌 下个地点

我们打着光脚在那风车下跑

等一下就回家怎么才到半山腰

就让那些烦恼都随风去吧

随着稻香飘过的地方耶哎呦喂

喜欢那时候风言风语

总是习惯悲中带着笑

喜欢被无视的童言无忌

被风车带走不在

风是从哪儿来手上的狗尾巴草摇的更剧烈

稻穗也晃起来我紧握着你的手把它拍成照片

我们俩转 就像大风车

早该逃离这我转转 把云卷散了

下个地方 风筝睡醒了

乘着它走吧 飘飘 等着大风车

像在画一幅油画

陶醉你的笑容

就沿着风车走吧

不用 猜忌 下个地点

点击右上角即可分享
微信分享提示