基于注解方式组件管理

基于注解方式组件管理

之前是通过在xml文件中向ioc容器中配置bean,通过<bean 标签的方式,注解的方式是在Java类上使用注解标记某个类,将该类配置到ioc容器。

主要分成两步:

  • 在类上使用注解

  • 让ioc识别那些类加了注解

1.注解的ioc配置

spring提供了以下几个注解,直接标记在类上,把他们定义成bean组件

  • @Component 该注解用于描述Spring中的bean,当一个类的功能不是controller、service、dao时,可以使用该注解

  • @Repository 该注解用于dao层的类

  • @Service 该注解用于 service层

  • @Controller 该注解用于 Controller层

package com.ztone.ioc_01.component;
​
import org.springframework.stereotype.Component;
​
@Component
public class HappyComponent {
}
​
@Controller
public class HappyController {
}

一个注解就相当于是一个bean标签,<bean id="happyController" class="HappyController"/>

后三个和@Component没有本质区别,只是能够清晰分辨类是哪一层的,在源码中后三个都使用了@Component来注解

image-20240715202726789

 

标记好类之后,在配置文件指定扫描哪个包下的注解,使用context:component-scan 标签

  • 第一种方式

    普通配置包扫描,context:component-scan 标签的 base-package属性指定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"
           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 https://www.springframework.org/schema/context/spring-context.xsd">
    ​
        <context:component-scan base-package="com.ztone.ioc_01"/>
    </beans>
  • 第二种

    扫描包后,可以排除某些注解,在context:component-scan 标签下,使用context:exclude-filter 标签来指定排除哪些注解,属性type是 annotation表示排除的类型是注解,expression是注解的全限定符

    <context:component-scan base-package="com.ztone.ioc_01">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    </context:component-scan>
  • 第三种

    指定了扫描包后,指定只想要的注解,标签是 context:include-filter,需要在context:component-scan 注解加上 user-default-filter="false" 属性,表示指定包下的注解先不生效

    <context:component-scan base-package="com.ztone.ioc_01" user-default-filter="false" >
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
    </context:component-scan>

 

Bean的name

在@Component、@Controller、@Service、@Repository 注解中可以使用value来指定该 组件的name

@Component(value = "happy")
public class HappyComponent {
}

如果只有一个value属性,那么value可以省略

在不指定value的情况时,组件的id就是 类名首字母小写

 

2.生命周期方法和作用域

通过注解指定生命周期方法

  • @PostConstruct 在初始化方法的上使用该注解

  • @PreDestroy 在销毁方法上使用该注解

指定bean的作用域使用的注解是 @Scope

注解中使用scopeName 属性指定是单例还是多例

  • ConfigurableBeanFactory.SCOPE_SINGLETION 单例,也是默认值

  • ConfigurableBeanFactory.SCOPE_PROTOTYPE 多例

@Component
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public class JavaBean {
    
    @PostConstruct
    public void init(){
        
    }
    
    @PreDestroy
    public void destory(){
        
    }
}

 

 

3.注解的di配置

在一个组件中引用了另一个组件时,之前在xml中是通过在引用组件配置的标签内使用property 注入 被引用组件

现在直接在类中,引入属性的地方使用 @Autowired,进行自动装配。

@Controller
public class UserController {
    
    @Autowired
    private UserService userService;
}

不仅可以在成员变量上使用,还可用在构造方法和set方法上

@Autowired 的工作流程是:

  • 首先根据组件的类型进行装配

    • 如果能够找到唯一的bean则直接进行装配

    • 如果找不到则装配失败

  • 如果找到的bean 不止一个,那么就会根据成员变量的名字作为bean的id

    在这里可以使用 @Qualifier 来指定名称来作为 bean的id,如果没有指定,那么就会使用成员变量的变量名。

    public interface UserService {
        
    }
    ------
    @Service
    public class UserServiceImpl implements UserService{
    }
    ------
    @Service
    public class NewUserServiceImpl implements UserService{
        
    }

    现在有两个类都实现了 UserService 接口,在UserController 中还使用 接口去接收变量,属性名区分不开这两个类,就可以使用 @Qualifier

    @Controller
    public class UserController {
    
        @Autowired
        @Qualifier(value = "userServiceImpl")
        private UserService userService;
    }

    @Qulifier注解必须搭配 @Autowired使用,value的值,只能是属性的类型首字母小写或者是在@Component、@Conreoller...... 这种注解中指定的名字

Java提供了@Resource 注解,他的效果等同于 @Autowired + @Qulifier

要使用这个注解,在JDK版本高于11 或低于8 要引入依赖

@Controller
public class UserController {

    @Resource(value = "userServiceImpl")
    private UserService userService;
}

 

上面是引用类型的di配置,那么基本类型如何进行di配置呢?

使用的注解是 @Value

@Component
public class JavaBeanValue {
    
    @Value("zhangsan")
    private String name;
    
    private int age = 18;
    
}

一般基本类型都像age一样直接赋值。那么@Value 存在意义是什么呢?

@Value 可以读取文件中的数据

<context:component-scan base-package="com.ztone.ioc_03"/>

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

首先扫描包下的注解,并且读取外部的配置文件

studentname=tom
studentpassword=123456

在@Value注解中 用 ${xxxx} 读取

@Value("zhangsan")
private String name;

private int age = 18;

@Value("${studentname}")
private String studentName;

@Value("${studentpassword}")
private String password;

如果读取不到还可以在后面用 :xxxx 指定默认值

@Value("${studentname:admin}") private String studentName;

 

4.三层架构案例注解实现

首先还是准备依赖,实体类,这些不再赘述,在实体类上用@Component注解

  1. 准备controller,service,dao层

    package com.ztone.controller;
    
    import com.ztone.pojo.Student;
    import com.ztone.service.StudentService;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Controller;
    
    import java.util.List;
    
    @Controller
    public class StudentController {
    
        @Autowired
        private StudentService studentService;
    
        public void searchStudents(){
            List<Student> students = studentService.queryAllStudent();
            System.out.println(students);
        }
    }
    package com.ztone.service;
    
    import com.ztone.pojo.Student;
    
    import java.util.List;
    
    public interface StudentService {
        List<Student> queryAllStudent();
    }
    ------------------------------------
    package com.ztone.service;
    
    import com.ztone.dao.StudentDao;
    import com.ztone.pojo.Student;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.stereotype.Service;
    
    import java.util.List;
    
    @Service
    public class StudentServiceImpl implements StudentService{
    
        @Autowired
        private StudentDao studentDao;
        @Override
        public List<Student> queryAllStudent() {
            return studentDao.queryAllStudent();
        }
    }
    package com.ztone.dao;
    
    import com.ztone.pojo.Student;
    
    import java.util.List;
    
    public interface StudentDao {
        List<Student> queryAllStudent();
    }
    --------------------------------
    package com.ztone.dao;
    
    import com.ztone.pojo.Student;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.jdbc.core.BeanPropertyRowMapper;
    import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.stereotype.Repository;
    
    import java.util.List;
    
    @Repository
    public class StudentDaoImpl implements StudentDao{
        @Autowired
        private JdbcTemplate jdbcTemplate;
        @Override
        public List<Student> queryAllStudent() {
            String sql = "select id,name,gender,age,class as classes from students";
            List<Student> students = jdbcTemplate.query(sql, new BeanPropertyRowMapper<>(Student.class));
            return students;
        }
    }

    这里使用到了注解 @Controller、@Service、@Repository在相应的类上,然后在注入属性的时候用到了 @Autowired注解

  2. 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"
           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">
    
    
    
        <context:property-placeholder location="classpath:jdbc.properties"/>
    
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
            <property name="url" value="${url}"/>
            <property name="driverClassName" value="${driver}"/>
            <property name="username" value="${username1}"/>
            <property name="password" value="${password}"/>
        </bean>
    
        <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
            <property name="dataSource" ref="dataSource"/>
        </bean>
    
        <context:component-scan base-package="com.ztone"/>
    </beans>

    这个案例还是用 注解+xml的方式,自己定义的类用 注解注入到ioc容器,外部的类用xml方式

    使用注解不要忘记在xml中用 context:component-sacn 标签扫描包引入注解

     

遇到的问题:

扫描包要放在 引入 JdbcTemplate 后面,因为在StudentDao中用到了 JdbcTemplate,如果还没有将其注入ioc容器,就会报错。

posted @ 2024-07-18 19:29  GrowthRoad  阅读(5)  评论(0编辑  收藏  举报