Spring -ioc--基于注解方式
一.基于注解方式的ioc配置:
IoC和DI都是在IoC容器中进行的,在外部:我们只需要提供类的信息即可(组件类)
学习目标:
1.如何在类上加注解
2.如何在xml中配置 生效包的信息;
1.注解概述:
1.注解:注解和xml文件一样,注解本身并不能执行,注解仅仅是一个标记;
具体功能就是:框架检测到注解标记的位置,然后针对这个位置按照注解标记的功能来执行;
2.扫描:Spring 为了知道程序员在哪些地方标记了什么注解,就需要通过扫描的方式,来进行检测。然后根据注解进行后续操作。
在xml文件中配置!!!
2.组件添加标记注解
将组件配置到ioc容器之中:
我们可以直接使用注解进行配置 ,就不用用使用<bean>了
第(1)步:标记注解:eg:@Component
第(2)写一个配置文件,指定扫描包
(1)
注解:
@Component
|@Repository| 该注解用于将数据访问层(Dao 层)其功能与 @Component 相同。
@Service 用在service层
@Controller 用在Controller层
eg:
1.注解@Component就相当于原来的<bean>
2.本质上:这几个注解作用相同,我们只是可以根据这些组件来区分一下:是哪层的组件;
3.使用:直接将注解放到对应的类上即可!!!
4.加上注解之后:beanId(默认)标识就是类名的首字母小写
eg:
如何(指定)注解(指定注解名字):@Component(value="egz");
或者: @Component("egz");
(2)指定扫描包:
三种配置方式!!!
<!--普通配置包扫描:(最常用!!!)-->
<!--<context:component-scan base-package="a:指定ioc容器去哪些包下查找注解类;
b:base-package可以指定多个包:eg:包1,包2..."/>
c:指定包就相当于指定了包的所有类
-->
<context:component-scan base-package="com.atguigu.ioc_01"/>
<!--2.指定包,但排除指定注解-->
<context:component-scan base-package="com.atguigu.ioc_01">
<!--排除包下的指定注解:以排除Repository为例-->
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
<!--3.指定包,指定含注解-->
<context:component-scan base-package="com.atguigu" use-default-filters="false">
<!--base-package="com.atguigu"这句话默认是:扫描包下的全部注解
我们可以在后面加上:use-default-filters="false":指定包的所有注解先不生效
最后再根据包含的生效
-->
<!--比如我们只想要R注解:即只扫描这个com.atguigu包下的R注解,其它不要-->
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
二:扩展:周期方法和作用域注解
1.周期方法:
周期方法:在指定的时间执行的代码:
eg:在创建组件之后:调用init()
销毁组件之前:调用destroy()
可以在方法中做一些初始化/销毁工作
如何完成周期方法和作用域的配置:~!!!!!!!!!!!!
1.
如何使用注解方式在ioc容器中配置周期方法
a:准备组件类:将周期方法(init,destroy)放入类中:在组件类上使用注解eg:@Component将组件类放入ioc容器中
b:在对应的“ 方法 ”上方加上“ 注解 ”
@PostConstruct //注解制指定初始化方法
@PreDestroy //注解指定销毁方法
/注意:周期方法:命名随意,但必须是public void且没有形参
c:如何使用组件配置作用域:
:在类上面使用注解 @Scope;
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_SINGLETON) //单例,默认值
@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE) //多例 二选一
注意:单例会调用destroy方法
多例不会管destroy
三:使用注解进行DI配置:引用其它组件(对象)
1.如何实现DI配置:
我们想要将UserController引用UserService组件:
a: 在UserService类中:(定义全局变量):private UserService userService;(使用接口定义全局变量);
b: 直接在UserController层的属性private UserService userService;上面 添加 “ @Autowired ”
(ioc会根据类型自动装配!!!)
//使用“ 自动装配 ” 注解@Autowired注入
//这个注解是加在“成员变量”上的,不需要set方法,就相当于对属性/成员变量进行赋值操作:将组件赋值给组件;
//执行过程:ioc直接找对应类型的组件,找到以后直接进行装配:将组件赋值给组件;
2.代码实现
//UserService接口
public interface UserService {
public String show(); //接口中的抽象方法
}
@Service //!!!!我们是将UserServiceImpl放入ioc容器的!!
//UserService接口的实现类
public class UserServiceImpl implements UserService{
public String show(){ //实现接口的show方法
return "UserServiceImpl.show()";
}
}
//User的表述层
@Controller
public class UserController {
@Autowired //使用自动装配注解@Autowired注入:
// 对属性userService直接进行操作,直接将UserService直接注入它,无需set方法!!!!!
//工作原理:1.ioc容器查找符合类型的组件对象 2.设置给当前属性
private UserService userService; //UserService定义成全局变量;
//接口和实现类的对象相同:我们这里一般放接口!!!:即根据接口取值:放UserService
//调用业务层的show:
public void show(){
}
}
注意:
1. @Autowired 标记位置:
a:成员变量(最常用)
b:构造器
c:setter方法
2.在成员变量上方加上@Autowired:它会根据类型进行自动装配(将组件注入组件)
默认情况下:必须要有被注入的bean,没有就报错:
(1)有1个bean,就可以正常装配(将bean注入)
(2) 如果有多个bean:默认会根据Autowired对应成员属性名当中benaID进行查找指定的bean
(3)但如果成员变量的名字和这几个bean都不同/无关:查找不到
1..使用@Qualifer注解指定bean的名称: @Qualifer(value="BeanId");
:进行指定具体使用哪一个UserService类(组件)进行装配;(必须配合@Autowired使用)
2..使用整合注解:@Resource注解=@Autowired+Q注解
但是:是java提供的,由spring实现
使用方法:
导入依赖
@R(name="userServiceImp");
3.@Value注解:
如何对直接属性的DI配置:
1.直接属性赋值:DI动作:直接赋值即可,不用加@value注解
2. @value主要意义:读取外部的配置文件(在组件类中读取变量);eg:.properties
a:声明配置文件
b:将配置文件引入ioc容器中
c:在类上相应的属性上面加@value注解
@value("${key}")
就可以在组件类中读取变量password,username
3. 注意:默认值语法:当外部文件中没有 名称 eg:username,password,我们可以指定一个默认值:@Value("${key value:默认值}")
四:基于注解和xml方式整合三层架构案例
回顾:
想要将那个放入ioc:使用对应的注解:eg:@Component @Servcie @Controller @R
想要DI:@Autowired