小言_互联网的博客

Spring 基于注解的Ioc

478人阅读  评论(0)


1. 基于注解的Ioc配置

Spring基于XML文件配置的形式为:

<bean id="accountService" class="dyliang.service.impl.AccountServiceImpl">
    <property name="accountDao" ref="accountDao"></property>
</bean>

<bean id="accountDao" class="dyliang.dao.impl.IAccountDaoImpl">
    <property name="runner" ref="runner"></property>
</bean>

accountService和accountDao相对应的类实现代码为:

public class IAccountDaoImpl implements IAccountDao {

    @Autowired
    private QueryRunner runner;

    public List<Account> findAll() {
        try {
            return runner.query("select * from account", new BeanListHandler<Account>(Account.class));
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public Account findById(Integer id) {
        try {
            return runner.query("select * from account where id=?", new BeanHandler<Account>(Account.class), id);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void saveAccount(Account account) {
        try {
            runner.update("insert into account(name,money)values(?,?)",account.getName(),account.getMoney());
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void updateAccount(Account account) {
        try {
            runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void deleteAccount(Integer id) {
        try {
            runner.update("delete from account where id=?",id);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

public class AccountServiceImpl implements IAccountService {

    @Autowired
    private IAccountDao accountDao;

    public List<Account> findAll() {
        return accountDao.findAll();
    }

    public Account findById(Integer id) {
        return accountDao.findById(id);
    }

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

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

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

spring中提供了注解@Component来配置资源的管理,对于

<bean id="accountService" class="dyliang.service.impl.AccountServiceImpl"></bean>

的功能相同实现只需要在对应的类上使用注解@Component,如下所示:

@Component
public class AccountServiceImpl implements IAccountService {
    private IAccountDao accountDao;

    public void setAccountDao(IAccountDao accountDao) {
        this.accountDao = accountDao;
    }

    public List<Account> findAll() {
        return accountDao.findAll();
}

使用了注解@Component后,虽然在bean.xml文件中不需要配置<bean>,但需要配置<context:component-scan>来告诉spring在创建Ioc容器时应该扫描哪些包,即使用@Component注解的类所在的包

<context:component-scan base-package="dyliang"></context:component-scan>

同时导入约束时需要多导入一个context名称空间下的约束,启用注解

<?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
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

最后编写测试类来执行单元测试

public class AccountTest {

    @Test
    public void testFindAll() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService as = ac.getBean("accountService", IAccountService.class);
        List<Account> accounts = as.findAll();
        for (Account account : accounts) {
            System.out.println(account);
        }
    }

    @Test
    public void testFindOne() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        Account account = as.findById(1);
        System.out.println(account);
    }

    @Test
    public void testSave() {
        Account account = new Account();
        account.setName("test");
        account.setMoney(12345f);

        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        as.saveAccount(account);
    }

    @Test
    public void testUpdate() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        Account account = as.findById(4);
        account.setMoney(23456f);
        as.updateAccount(account);
    }

    @Test
    public void testDelete() {
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
        IAccountService as = ac.getBean("accountService",IAccountService.class);
        as.deleteAccount(4);
    }
}


2. 常用注解

2.1 创建对象

  • @Component:把资源让spring来管理,相当于在xml中配置一个bean。
    • 属性value:指定bean的id,如果不指定value属性,默认bean的id是当前类首字母小写的类名

@Controller @Service @Repository和@Component的作用相同,但是语义更加的明确,显式的指明了注解适合使用的地方。同样可使用value属性来指定具体的名字,因为只有value,所以也可以省略不写。

  • @Controller:一般用于表现层

  • @Service:一般用于业务层

    @Service("accountService")
    public class AccountServiceImpl implements IAccountService {}
    
  • @Repository:一般用于持久层

    @Repository("accountDao")
    public class IAccountDaoImpl implements IAccountDao {}
    

2.2 注入数据

  • @Autowired:自动按照类型注入。当使用注解注入属性时,set方法可以省略。它只能注入其他bean类型。当有多个类型匹配时,使用要注入的对象变量名称作为bean的id,在spring容器查找,找到了可以注入成功;找不到就报错。使用方式如下:

    @Service("accountService")
    public class AccountServiceImpl implements IAccountService {
    
        @Autowired
        private IAccountDao accountDao;
    }
    

    当使用时,程序就会在Ioc容器中中找id为accountDao,对应的class为IAccountDao的对象。如果有,则自动注入,否则报错。

  • @Qualifier:在自动按照类型注入的基础之上,再按照Bean的id注入。它在给字段注入时不能独立使用,必须和@Autowired一起使用;但是给方法参数注入时,可以独立使用

    • 属性value::指定bean的id
  • @Resource:直接按照Bean的id注入,它也能注入其他bean类型

    • 属性name:指定bean的id
  • @Value:注入基本数据类型和String类型数据的值

    • 属性value:用于指定值

2.3 改变作用范围

  • @Scope:指定bean的作用范围
    • 属性value:指定范围的值,取值:singleton、 prototype、 request 、session 、globalsession

2.4 生命周期

  • @PostConstruct : 用于指定初始化方法
  • @PreDestroy : 用于指定销毁方法

2.5 配置

  • @Configuration:用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration注解的类.class)

    • 属性value:用于指定配置类的字节码
  • @ComponentScan:用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的<context:component-scan base-package="dyliang"/>一样

    • 属性basePackages:用于指定要扫描的包
  • @Bean:该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器

    • 属性name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)
  • @PropertySource:用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置

    • 属性value[]:用于指定properties文件位置。如果是在类路径下,需要写上classpath:
  • @Import:用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解

    • 属性 value[]:用于指定其他配置类的字节码
public class JdbcConfig {

    @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(name="runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(@Qualifier("ds") DataSource dataSource){
        return new QueryRunner(dataSource);
    }

    @Bean(name="ds")
    public DataSource createDataSource(){
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

2.6 总结

基于XML配置 基于注解配置
Bean定义 <bean id="..." class="..."/> @Component即衍生类@Repository、@Service、@Controller
Bean名称 通过id或name指定 @Component("…")
Bean注入 <property>或者通过p命名空间 @Autowired按类型注入、@Qualifier按名称注入
生命过程、Bean作用范围 init-method、destroy-method;范围scope属性 @PostConstruct初始化、@PreDestroy销毁、@Scope设置作用范围
适合场景 Bean来自第三方,使用其他Bean Bean的实现类由用户自己开发

3. Spring整合Junit

  • 导入坐标

    <dependencies>
          <dependency>
              <groupId>org.springframework</groupId>
              <artifactId>spring-test</artifactId>
              <version>5.2.5.RELEASE</version>
          </dependency>
          <dependency>
              <groupId>junit</groupId>
              <artifactId>junit</artifactId>
              <version>4.12</version>
          </dependency>
      </dependencies>
    
  • 使用@RunWith注解替换原有运行器

    @RunWith(SpringJUnit4ClassRunner.class)
    public class AccountTest {}
    
  • 使用@ContextConfiguration指定spring配置文件的位置

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:bean.xml")
    public class AccountTest {}
    
  • 使用@Autowired给测试类中的变量注入数据

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(locations = "classpath:bean.xml")
    public class AccountTest {
    
        @Autowired
        private IAccountService as;
    }
    

完整的使用:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class AccountTest {

    @Autowired
    private IAccountService as;

    @Test
    public void testFindAll(){
        List<Account> all = as.findAll();
        for (Account account : all) {
            System.out.println(account);
        }
    }
}

4. 基于完全注解的CURD

4.1 创建表

首先需要在数据库中创建表,并插入数据:

create table account(
	id int primary key auto_increment,
	name varchar(40),
	money float
)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);

使用select查询:

mysql> select * from account;
+----+------+-------+
| id | name | money |
+----+------+-------+
|  1 | aaa  |  1000 |
|  2 | bbb  |  1000 |
|  3 | ccc  |  1000 |
+----+------+-------+
3 rows in set (0.00 sec)

4.2 创建工程

创建Maven工程,然后导入需要的pom.xml中导入需要的坐标:

<?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>org.example</groupId>
    <artifactId>SpringAllAnnotationAccount</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>

    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.2.5.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>
        <dependency>
            <groupId>commons-dbutils</groupId>
            <artifactId>commons-dbutils</artifactId>
            <version>1.4</version>
        </dependency>
        <dependency>
            <groupId>c3p0</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.1.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

4.3 创建实体类

创建对应于表的实体类,并实现序列化接口:

public class Account implements Serializable {

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

4.4 持久层

public interface IAccountDao {

    List<Account> findAll();

    Account findById(Integer id);

    void saveAccount(Account account);

    void updateAccount(Account account);

    void deleteAccount(Integer id);
}
@Repository("accountDao")
public class IAccountDaoImpl implements IAccountDao {

    @Autowired
    private QueryRunner runner;

    public List<Account> findAll() {
        try {
            return runner.query("select * from account", new BeanListHandler<Account>(Account.class));
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public Account findById(Integer id) {
        try {
            return runner.query("select * from account where id=?", new BeanHandler<Account>(Account.class), id);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void saveAccount(Account account) {
        try {
            runner.update("insert into account(name,money)values(?,?)",account.getName(),account.getMoney());
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void updateAccount(Account account) {
        try {
            runner.update("update account set name=?,money=? where id=?",account.getName(),account.getMoney(),account.getId());
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }

    public void deleteAccount(Integer id) {
        try {
            runner.update("delete from account where id=?",id);
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

4.5 业务层

public interface IAccountService {
    List<Account> findAll();

    Account findById(Integer id);

    void saveAccount(Account account);

    void updateAccount(Account account);

    void deleteAccount(Integer id);
}

@Service("accountService")
public class AccountServiceImpl implements IAccountService {

    @Autowired
    private IAccountDao accountDao;

    public List<Account> findAll() {
        return accountDao.findAll();
    }

    public Account findById(Integer id) {
        return accountDao.findById(id);
    }

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

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

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

4.6 配置类

public class JdbcConfig {
    @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(name="runner")
    @Scope("prototype")
    public QueryRunner createQueryRunner(@Qualifier("ds") DataSource dataSource){
        return new QueryRunner(dataSource);
    }

    @Bean(name="ds")
    public DataSource createDataSource(){
        try {
            ComboPooledDataSource ds = new ComboPooledDataSource();
            ds.setDriverClass(driver);
            ds.setJdbcUrl(url);
            ds.setUser(username);
            ds.setPassword(password);
            return ds;
        }catch (Exception e){
            throw new RuntimeException(e);
        }
    }
}

@ComponentScan("dyliang")
@Import(JdbcConfig.class)
@PropertySource("classpath:jdbcConfig.properties")
public class SpringConfiguration {
}

其中配置文件jdbcConfig.properties内容为:

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/sql_store?serverTimezone=GMT
jdbc.username=root
jdbc.password=1234

4.7 单元测试

最后,编写测试类并执行单元测试:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfiguration.class)
public class AccountTest {

    @Autowired
    private IAccountService as = null;

    @Test
    public void testFindAll() {
        List<Account> accounts = as.findAll();
        for(Account account : accounts){
            System.out.println(account);
        }
    }

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

    @Test
    public void testSave() {
        Account account = new Account();
        account.setName("test anno");
        account.setMoney(12345f);
        as.saveAccount(account);

    }

    @Test
    public void testUpdate() {
        Account account = as.findById(4);
        account.setMoney(23456f);
        as.updateAccount(account);
    }

    @Test
    public void testDelete() {
        as.deleteAccount(4);
    }
}

t> accounts = as.findAll();
for(Account account : accounts){
System.out.println(account);
}
}

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

@Test
public void testSave() {
    Account account = new Account();
    account.setName("test anno");
    account.setMoney(12345f);
    as.saveAccount(account);

}

@Test
public void testUpdate() {
    Account account = as.findById(4);
    account.setMoney(23456f);
    as.updateAccount(account);
}

@Test
public void testDelete() {
    as.deleteAccount(4);
}

}



转载:https://blog.csdn.net/Forlogen/article/details/106946322
查看评论
* 以上用户言论只代表其个人观点,不代表本网站的观点或立场