Spring系列之新注解配置+Spring集成junit+注解注入

时间:2022-07-25
本文章向大家介绍Spring系列之新注解配置+Spring集成junit+注解注入,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

Spring系列之注解配置

Spring是轻代码而重配置的框架,配置比较繁重,影响开发效率,所以注解开发是一种趋势,注解代替xml配置文件可以简化配置,提高开发效率 你本来要写一段很长的代码来构造一个Beam对象,但是如果使用注解的话只要使用一个注解符号即可

下面我们来讲讲一些经常使用的注解符号 @Component 使用类上用于实例化Bean @Controller 使用web层类上用于实例化Bean @Service 使用在Service层类上用于实例化service @Repository 使用在dao层类上用于实例化Bean @Autorwired 使用在字段上用于根据类型依赖注入 @Qualifier 结合结合@Autowired一起使用根据名称进行依赖注入 @Resource 相当于@Autowired+@Qualifier一起使用 @Scope 标注bean的范围 @PostConstruct 使用该在方法上标注该方法是Bean的初始化方法 @PostDestory 使用在方法上标注该方法是Bean的销毁方法

这三个没有什么区别,不过是为了在后期读代码的时候更加利于我们区分,比如看到@Controller就知道这是web层,看到@Service就知道这是service层

@Component  使用类上用于实例化Bean
@Controller    使用web层类上用于实例化Bean
@Service        使用在Service层类上用于实例化service
@Repository   使用在dao层类上用于实例化Bean

所以我们只需讲一个即可,其他的使用方法均相同,这里我们使用@Component来讲解 定义一个userDaolmp类

package com.pjh.dao;
import com.pjh.dao.Imp.userdao;
import org.springframework.stereotype.Component;
@Component("userDaoImp")
public class userDaoImp implements userdao {
    public void save() {
        System.out.println("save");
    }
}

定义一个测试类测试

@Test
    public void test(){
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
      userdao userDaoImp =(userdao) classPathXmlApplicationContext.getBean("userDaoImp");
      userDaoImp.save();
    }

然后我们就发现了如下报错 由蓝色的划线部分我们可以看出问题是:没有一个名叫userDaoImp的bean

这是为什呢?因为我们虽然写了注解,但是我们要让applicationContext.xml知道我们使用了注解,要告诉他哪里有个bean。所以我们在applicationContext中还需要加入以下配置

命名空间:xmlns:context="http://www.springframework.org/schema/context 约束路径http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd 注解的组件扫描: <context:component-scan base-package="com.pjh"/>

成功运行

接下来我们再来讲讲如何使用注解进行注入

方式一:使用@Autowired+@Qualifier 目的:创建一个userdao类将其注入带service类中

userdao类代码

package com.pjh.dao;
import com.pjh.dao.Imp.userdao;
import org.springframework.stereotype.Component;
@Component("userDaoImp")
public class userDaoImp implements userdao {
    public void save() {
        System.out.println("save");
    }
}

service类代码

package com.pjh.service.Imp;
import com.pjh.dao.Imp.userdao;
import com.pjh.dao.userDaoImp;
import com.pjh.service.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import javax.xml.bind.SchemaOutputResolver;

@Repository("serviceImp")
public class serviceImp implements service {
   @Autowired
   @Qualifier("userDaoImp")
   
   private userDaoImp userDaoImp;
    public void save() {
        System.out.println("sssssss");
       userDaoImp.save();
    }

}

测试类

@Test
    public void test(){
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
      service service =(service) classPathXmlApplicationContext.getBean("serviceImp");
      service.save();
    }

结果

方式二:使用@Resource()

就是把 @Autowired + @Qualifier("userDaoImp")换成@Resource(name="userDaoImp"),其余代码均与方式一相同

package com.pjh.service.Imp;
import com.pjh.dao.Imp.userdao;
import com.pjh.dao.userDaoImp;
import com.pjh.service.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Repository;
import javax.annotation.Resource;
import javax.xml.bind.SchemaOutputResolver;
@Repository("serviceImp")
public class serviceImp implements service {
  /* @Autowired
   @Qualifier("userDaoImp")*/
    @Resource(name="userDaoImp")
   private userDaoImp userDaoImp;
    public void save() {
        System.out.println("sssssss");
       userDaoImp.save();
    }

}

结果

令人蛋碎的事情来了,报错了,意思是不支持版本5

解决方案: File->setting下设置项目的jdk版本

File->ProjectStruct下设置版本

结果

又报错了,这。。。。。我tm心态崩了呀

根据报错的内容是报了个空指针异常,这是为什么呢?为什么使用@Autowired + @Qualifier("userDaoImp")不报错换成@Resource(name="userDaoImp")就报空指针呢

原因:jdk版本不支持

解决方案:

1.更换本地的jdk版本,最好jdk1.8以上,jdk9不支持有bug 2.再maven.pom文件中引入如下依赖

<dependency>
        <groupId>org.apache.tomcat</groupId>
        <artifactId>tomcat-annotations-api</artifactId>
        <version>7.0.47</version>
    </dependency>

结果 成功运行

终于解决完了

使用@Scope注解标注Bean的范围 使用@Scope("prototype")

package com.pjh.dao;
import com.pjh.dao.Imp.userdao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component("userDaoImp")
@Scope("prototype")
public class userDaoImp implements userdao {
    public void save() {
        System.out.println("save");
    }
}

测试代码

@Test
    public void test(){
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        userdao userdao =(userdao) classPathXmlApplicationContext.getBean("userDaoImp");
        userdao userdao1 =(userdao) classPathXmlApplicationContext.getBean("userDaoImp");
        System.out.println(userdao);
        System.out.println(userdao1);
    }

结果

使用@Scope("singleton")

package com.pjh.dao;
import com.pjh.dao.Imp.userdao;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component("userDaoImp")
@Scope("singleton")
public class userDaoImp implements userdao {
    public void save() {
        System.out.println("save");
    }
}

结果

在这里顺便给大家复习复习singleton与prototype的区别吧 singleton Bean的实例化个数:1个 Bean的实例化时机:当Spring核心配置文件被加载时 Bean的生命周期: 对象创建:当应用加载时对象创建 对象运行:只要容器在,对象就一直活着 对象销毁:当应用卸载,容器销毁时 prototype:在使用getBean方法的时候创建bean prototype Bean的实例化格式:多个 Bean的实例化时机:当调用getBean()方法时,实例化Bean 对象创建:当使用对象时,创建新的对象实例 对象运行:只要对象在使用中,对象就一直存在 对象销毁:对象长时间不使用,就会被java的垃圾回收机制回收

初始化方法和销毁方法

初始化方法 @PostConstract

@PostConstruct
    public void constract(){
        System.out.println("初始化方法");
    }

销毁方法 @PostDestroy

 @PreDestroy
    public void  destroy(){
        System.out.println("在对象销毁前执行");
    }

@Value()进行注入

package com.pjh.dao;
import com.pjh.dao.Imp.userdao;
import com.sun.scenario.effect.impl.sw.sse.SSEBlend_SRC_OUTPeer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component("userDaoImp")
@Scope("singleton")
public class userDaoImp implements userdao {
    public void save() {
        System.out.println("save");
        System.out.println("读取配置文件:"+one);
        System.out.println("普通类型:"+a);
    }
    @Value("${one.one}")
    private String one;
    @Value("4")
    private String a;

}

配置文件信息

one.one=1

applicationContext中添加的内容

 <context:property-placeholder location="classpath*:one.properties"/>

测试代码

@Test
    public void test(){
        ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        userdao userdao =(userdao) classPathXmlApplicationContext.getBean("userDaoImp");
        userdao.save();
    }

结果

使用上面的注解还不可以全部替代xml配置文件,还需要使用注解替代的配置如下 非自定义的Bean的配置: 加载properties文件的配置:<context:property-placeholder> 注解扫描的配置:context:component-scan 引入其他文件:

Spring新注解

@Configuration 用于指定当前类是一个Spring配置类,创建容器时会从该类上加载注解,该类不能是匿名类与final类 @ComponentScan 用于指定Spring在初始化容器的时候要扫描包 作用与Spring中的此代码相同:context:component-scan @Bean 使用方法,将该方法的返回值返回到容器中 @Import 用于导入其他配置类 @PropertySource 用于加载properties文件中的配置

案例

核心配置类

package com.pjh.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.stereotype.Component;
/*标志该类是核心配置类*/
@Configuration
/*扫描包*/
@Component("com/pjh")
/*导入其他配置类*/
@Import(DataSourceConfig.class)
public class Springconfig {
}

副配置类

package com.pjh.config;
import com.mchange.v2.c3p0.ComboPooledDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.PropertySource;
import javax.sql.DataSource;
import java.beans.PropertyVetoException;
/*加载配置文件*/
@PropertySource("classpath:jdbc.properties")
public class DataSourceConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    /*Spring会将当前方法的返回值以指定名称存储到Spring容器中*/
    @Bean("dataSource")  
    public DataSource getDataSource() throws PropertyVetoException {
        ComboPooledDataSource dataSource = new ComboPooledDataSource();
        dataSource.setDriverClass(driver);
        dataSource.setJdbcUrl(url);
        dataSource.setUser(username);
        dataSource.setPassword(password);
        return dataSource;
    }
}

测试函数

@Test
    public void test() throws SQLException {
        ApplicationContext applicationContext = new
                AnnotationConfigApplicationContext(Springconfig.class);
      DataSource bean = (DataSource)applicationContext.getBean("dataSource");
        Connection connection = bean.getConnection();
        System.out.println(connection);
    }

结果 成功创建connection连接

Spring集成junit

为什么使用Spring集成junit? 在测试类中每个类都要写下面的两行代码

ApplicationContext applicationContext = new
                AnnotationConfigApplicationContext(Springconfig.class);
      DataSource bean = (DataSource)applicationContext.getBean("dataSource");

这两行代码的作用是获取容器,不写的话报空指针异常 为了让我们测试的时候不用进行反复的写上述两行的操作,我们使用Spring来集成junit,用springjunit来创建spring容器, 我们只需将配置文件的名称告诉他们即可,将需要的bean直接在容器中进行注入

Spring集成junit的步骤

需要导入的jar包

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