2、spring框架-依赖注入

spring框架-依赖注入

注解方式实现IOC和DI

@Component

控制反转的实现,加上这个注解后,spring根据包扫描会自动的扫描到这个注解将这个类创建对象交给spring容器。

xml方式:需要引入aop的架包

//包扫描
<context:component-scan base-package="cn.zj.spring"/>

@Component注解会在spring容器创建的时候扫描到这个注解,spring会为它创建对象

默认情况下名字是类名首字母小写 比如:userService

有一个value属性可以配置对当前的对象取name,相当于,没有id

@Component(value = "s1,s2,s3")

简写:

@Component("s1,s2,s3")

还有其他的跟@Component功能相同的注解,用语义来区分。

@Controller:用于web层

@Service:用于服务层

@Repository:用于持久层

一般来说都是可以在其他层的,只是从语义上更好的理解该类的作用。

@ControllerspringMcv的时候只能用这个

@Autowired+@Qualifier

/*
* DI依赖注入的方式:
* @Autowired+@Qualifier
* @Resource
*
* @Autowired:类型注入,类型当前类的类型自动去spring容器中找对象
* 如果接口有多个实现类,就会抛:No qualifying bean of type 异常
* 解决方案:
* 加上@Qualifier注解,指定注入的是哪个对象。
* @Qualifier(value = "service1"):
* value可省略,用来指定类型注入的是哪一个对象
* 如果没有找到所要注入的对象会报:NoSuchBeanDefinitionException: No qualifying bean of type
*
* 解决方式:
* @Autowired(required = false),虽然spring的问题解决了,但是
* 你使用了对象,就会报:java.lang.NullPointerException
*
*
* 类型注入的几种方式:
* 1.字段的注入,注解直接贴到字段上或叫成员变量
* 2.方法的注入:注解直接贴到方法上面
* 3.构造函数注入:直接写一个有参数的构造函数
* 注意:构造函数注入不用写@Autowired,默认就是使用这个,就算写了也不起作用
*/
//1.字段的注入
//@Autowired
//@Qualifier(value = "service1")
private UserService userService;
//2.方法的注入
//@Autowired
//@Qualifier("service2")//有多个实现类
public void setUserService(UserService userService) {
this.userService = userService;
}
//3.构造函数注入,多个实现类需要放在参数上@Qualifier("service2")
public UserController(@Qualifier("service2") UserService userService) {
this.userService = userService;
}

@Resource

/*
* @Resource注解也可以注入对象,是java官方提供的,spring只是实现了其功能
* 如果有多个实现类,需要用到name属性:@Resource(name = "service2")
*
* 注入的方式:
* 1.字段注入
* 2.方法注入
* @Resource没有构造器注入,跟@Autowired不同
*/
//1.字段注入
//@Resource(name = "service2")
private UserService userService;
//2.方法注入
@Resource(name = "service1")
public void setUserService(UserService userService) {
this.userService = userService;
}

全注解的方式

我们发现,之所以我们现在离不开xml配置文件,是因为我们有一句很关键的配置:

​ <context:component-scan base-package="cn.zj.spring"> </context:component-scan>

如果他要也能用注解配置,那么我们就可以脱离xml文件了。

通过@Configuration注解和@ComponentScan注解

替换XML配置文件的@Configuration注解 @Configuration配置类注解,在纯注解配置中,类加了该注解,就意味着该类是Spring的配置类。该类的功能就是用于替代原来的XML配置文件。 作用: 用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationConfigApplicationContext(有@Configuration注解的类.class)。
@ComponentScan注解 @ComponentScan注解扫描类,作用就是配置扫描Spring组件类的路径。功能等同原来配置文件的--作用: 用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的:<context:component-scan base-package="cn.zj.spring"/>是一样的。--属性: basePackages:用于指定要扫描的包。和该注解中的value属性作用一样。
@PropertySource注解 作用: 用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置。属性: value[]:用于指定properties文件位置。如果是在类路径下,需要写上classpath:
@Bean注解 作用: 该注解只能写在方法上,使用此方法创建一个对象,并且放入spring容器。它就相当于我们之前在xml配置中介绍的<bean标签> 属性: name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)。
@Import注解 作用: 用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解。当然,写上也没问题。属性: value[]:用于指定其他配置类的字节码。
@Value注解 读取properties配置文件以后, 使用 ${key}获取配置文件中对应的值 @Vlaue(“${jdbc.dirverClassName}”)private String driverClassName;
package cn.zj.spring.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
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 org.springframework.context.annotation.PropertySource;
import com.alibaba.druid.pool.DruidDataSource;
import com.spring.Config.SpringConfig2;
/*
* @Configuration 告诉程序我是Spring容器
* ------------------------------------------------------------
*@ComponentScan(basePackages = {"cn.zj.spring"})
* @ComponentScan:是用来配置需要扫描包,然后扫描类中的注解,
* 与<context:component-scan base-package="cn.zj.spring"/>功能相同。
*可以配置扫描多个包。
* 简写:
* @ComponentScan("cn.zj.spring")
*------------------------------------------------------------
* @PropertySource:读出xxx.properties的配置文件的注解
* classpath:固定写法,是用来读取配置文件的
* 相当于:<context:property-placeholder location="classpath:db.properties" />
*-----------------------------------------------------------
* @Value : 根据key获取配置文件中的value。有一个value的属性可省略
* 还可以写字符串或基本数据类
* 读value使用spring的EL表达式 ${key}
*-----------------------------------------------------------
*在new AnnotationConfigApplicationContext(class<T>...),可以传入多个配置类
*@import:导入其他配置类的类
*@Import(SpringConfig2.class),传入一个字节码文件,.class
* 相当于:<import resource=""/>
*/
@Configuration
//@ComponentScan(basePackages = {"cn.zj.spring"})
@ComponentScan("cn.zj.spring")
@PropertySource("classpath:db.properties")
@Import(SpringConfig2.class)
public class SpringConfig {
@Value("${jdbc.driverClassName}")
private String driverClassName;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
@Value("10")
private int maxActive;
/*
* 数据库连接池的创建
*
* @Bean:告诉spring容器我是一个需要创建的对象,也叫方法注入
* 告诉spring容器我需要创建对象,相当于 <bean/>
* @Scope:还可以在下面设置对象是单例还是多例
*
*/
@Bean(name = "dataSource", initMethod = "init", destroyMethod = "close")
@Scope
public DataSource getDataSource() {
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(this.driverClassName);
dataSource.setUrl(this.url);
dataSource.setUsername(this.username);
dataSource.setPassword(this.password);
dataSource.setMaxActive(this.maxActive);
return dataSource;
}
}

spring测试

在spring中集成了单元测试的包,我们在junit测试的时候总是要写很多次配置文件,还有写从spring容器中获取对象。图解如下:

传统的测试:

存在问题:

1,每个测试都要重新启动Spring容器,启动容器的开销大,测试效率低下。

2,不应该是测试代码管理Spring容器,应该是Spring容器在管理测试代码。

正确的使用方式:

将junit交给spring容器管理,而不是spring容器在junit的一个方法中,交给spring管理后,junit与bean之间就可以相互注入了。

执行步骤:

  1. 导入test依赖包

  1. 使用@RunWith注解

    //将Junit交给spring容器
    @RunWith(SpringJUnit4ClassRunner.class)
  2. 使用@ContextConfiguration注解

    //加载配置文件
    @ContextConfiguration(classes = SpringConfig.class)

注意:

Spring测试必须保证Eclipse的单元测试的最低版本是 4.12版本,如果使用的Eclipse版本很低,那么单元测试版本可能低于4.12,那么需要开发者手动导入单元测试的jar包

案例:

//先让junit在spring容器中运行
@RunWith(SpringJUnit4ClassRunner.class)
//加载配置文件
@ContextConfiguration(classes = SpringConfig.class)
public class UserTest {
@Autowired
private UserController userController;
@Test
public void testBean() {
userController.say();
}
@Test
public void testInsert() {
userController.insert();
}
}

spring-jdbc

Spring对象也支持JDBC,对JDBC只进行了薄薄的一层封装

问题: Java开发已经有JDBC,为什么Spring还要支持JDBC操作呢?

最重要的原因: Spring操作JDBC能自动管理事务

步骤:

  1. 导入依赖包spring-jdbc,spring-tx

  1. 创建JdbcTempalte对象在spring容器中

    //获取springJdbcTempalte
    @Bean
    @Scope("prototype")
    public JdbcTemplate getJdbcTemplate() {
    JdbcTemplate jdbcTemplate = new JdbcTemplate(getDataSource());
    return jdbcTemplate;
    }
  2. 操作数据库的增删改查

    package cn.zj.spring.dao.impl;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.List;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.core.RowMapper;
    import org.springframework.stereotype.Repository;
    import cn.zj.spring.dao.UserDao;
    import cn.zj.spring.pojo.User;
    @Repository
    public class UserDaoImpl implements UserDao {
    // 获取JdbcTempalte
    @Autowired
    private JdbcTemplate jdbcTemplate;
    @Override
    public void insert(User user) {
    String sql = "insert into t_user(name,email) values(?,?)";
    this.jdbcTemplate.update(sql, user.getName(), user.getEmail());
    }
    @Override
    public void deleteByPrimaryKey(Integer id) {
    String sql = "delete from t_user where id = ?";
    this.jdbcTemplate.update(sql, id);
    }
    @Override
    public void updateByPrimaryKey(User user) {
    String sql = "update t_user set name = ?, email = ? where id = ? ";
    this.jdbcTemplate.update(sql, user.getName(), user.getEmail(), user.getId());
    }
    @Override
    public User selectByPrimaryKey(Integer id) {
    String sql = "select * from t_user where id = ?";
    Object[] objs = { id };
    User user = this.jdbcTemplate.queryForObject(sql, objs, new RowMapper<User>() {
    @Override
    public User mapRow(ResultSet rs, int idx) throws SQLException {
    User user = new User();
    user.setId(rs.getInt("id"));
    user.setName(rs.getString("name"));
    user.setEmail(rs.getString("email"));
    return user;
    }
    });
    return user;
    }
    @Override
    public List<User> selectList() {
    String sql = "select * from t_user";
    List<User> users = this.jdbcTemplate.query(sql, new RowMapper<User>() {
    @Override
    public User mapRow(ResultSet rs, int arg1) throws SQLException {
    User user = new User();
    user.setId(rs.getInt("id"));
    user.setName(rs.getString("name"));
    user.setEmail(rs.getString("email"));
    return user;
    }
    });
    return users;
    }
    }
posted @   站着说话不腰疼  阅读(132)  评论(0编辑  收藏  举报
编辑推荐:
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 提示词工程——AI应用必不可少的技术
· 字符编码:从基础到乱码解决
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示