基于注解方式组件管理
之前是通过在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来注解
标记好类之后,在配置文件指定扫描哪个包下的注解,使用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注解
-
准备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注解
-
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 标签扫描包引入注解
遇到的问题: