目录
3.1 @Component、@Service、@Controller、@Resository
一、引言:
Spring-ioc的使用,需要我们通过xml将类声明给spring容器进行管理,从而通过spring工厂完成对象的创建及属性值的注入。spring除了基于xml的配置方式,同时提供了注解的配置,直接在实体类添加注解声明给spring容器进行管理,以简化开发步骤
二、项目部署:
2.1 创建maven项目:
使用web模板创建即可,此步骤略~
2.2 添加spring依赖:
maven工程中我们不再需要一个个进行jar的手动导入,只需要在pom.xml文件中添加依赖即可,jar包就会进行自动导入,在spring中,我们共需要五个包,我们只需要添加一个依赖即可“spring-context”,其他四个会自动添加部署项目中,所需的依赖可以到maven仓库中进行查找,网址:https://mvnrepository.com,具体代码如下:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.3.18</version>
</dependency>
添加后,在项目的右侧菜单中,在maven project的dependencies可以查看导入的jar包,是否导入成功,添加成功后如图所示:
2.3 创建spring配置文件
因为spring容器初始化时,只会加载applicationContext.xml主配置文件,那么我们在实体类中添加的注解就不会被spring扫描,所以我们需要在applicationContext.xml配置文件声明spring的扫描范围,以此达到spring初始化时扫描带有注解的实体类并完成初始化操作,在之前的项目中我们添加过一次applicationContext.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"
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">
</beans>
2.4 声明使用注解配置
配置文件声明spring的扫描范围后,我们还需要声明使用注解配置,并声明spring容器注解的扫描范围~具体实现代码如下:
<?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"
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:annotation-config/>
<!--声明Spring工厂注解的扫描范围-->
<context:component-scan base-package="com.xgsm.ioc.entity"/>
</beans>
三、常见注解:
3.1 @Component、@Service、@Controller、@Resository
将实体类中添加@Component,即将该实体类交给spring容器进行管理;@Component中有value属性,当不添加的时候相当于id为实体类名的首字母小写,也可以自定义id,例如:设置id为“stu”:@Component(value=“stu”)或@Component(“stu”)value可以省略:
实体类:@Component无参数 | 测试类 |
package com.xgsm.ioc.entity; import org.springframework.stereotype.Component; @Component public class Student { private int StuNum; private String StuName; private ClassRoom classRoom; public void setStuNum(int stuNum) { StuNum = stuNum; } public void setStuName(String stuName) { StuName = stuName; } public void setClassRoom(ClassRoom classRoom) { this.classRoom = classRoom; } } | package com.xgsm.ioc.Test; import com.xgsm.ioc.entity.Student; import org.springframework.context.support.ClassPathXmlApplicationContext; public class test { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); Student student = (Student) context.getBean("student"); System.out.println(student); } } |
根据测试结果我们可以知道,此时spring已经为我们创建了对象,并将id设置“student”,即实体类名的首字母小写
@Service、@Controller、@Resository和@Component有一个相同的功能就是,在类中声明该类注解,都是声明此类别spring容器进行管理,相当于applicationContext.xml主配置文件中的<bean>这个标签的作用;他们之间的区别有以下几点:
- @Controller注解主要是声明将控制类配置给Spring管理,例如servlet
- @Service注解主要是声明业务处理类配置给spring管理,例如Service
- @Repository注解主要声明持久化类配置给spring管理,例如Dao接口
- @Component除了控制器、service和Dao之外的类一律使用此注解
3.2 @Scope
@Scope 是类注解,用于声明当前类是单例模式还是非单例模式,相当于bean标签的Scope属性,@Scope (“prototype”)表示当前类为非单例模式,默认为单例模式
实体类@Scope (“prototype”)非单例模式 | 测试类 |
package com.xgsm.ioc.entity; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Scope("prototype") public class Student { private int StuNum; private String StuName; private ClassRoom classRoom; public void setStuNum(int stuNum) { StuNum = stuNum; } public void setStuName(String stuName) { StuName = stuName; } public void setClassRoom(ClassRoom classRoom) { this.classRoom = classRoom; } } | package com.xgsm.ioc.Test; import com.xgsm.ioc.entity.Student; import org.springframework.context.support.ClassPathXmlApplicationContext; public class test { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); Student student = (Student) context.getBean("student"); Student student1 = (Student) context.getBean("student"); System.out.println(student); System.out.println(student1); } } |
从测试结果中可以看到,由于这里我们采取的非单例模式,所以student和student1的值并不相同
3.3 @Lazy
@Lazy 类注解,用于声明一个单例模式的bean是否为“懒汉模式”,@Lazy(true)表示声明为懒汉模式
实体类@Lazy(true)懒汉模式 | 测试类 |
package com.xgsm.ioc.entity; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; @Component @Scope("prototype") @Lazy(true) public class Student { private int StuNum; private String StuName; private ClassRoom classRoom; public Student() { System.out.println("无参构造器"); } public void setStuNum(int stuNum) { StuNum = stuNum; } public void setStuName(String stuName) { StuName = stuName; } public void setClassRoom(ClassRoom classRoom) { this.classRoom = classRoom; } } | package com.xgsm.ioc.Test; import com.xgsm.ioc.entity.Student; import org.springframework.context.support.ClassPathXmlApplicationContext; public class test { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); Student student = (Student) context.getBean("student"); System.out.println(student); } } |
根据测试结果我们可以不难看出,懒汉模式是在实例化之后,创建对象的
3.4 @Postconstruct
@Postconstruct是方法注解,声明一个方法为当前类的初始化方法(在构造器之后执行),相当于bean标签的init-method属性
package com.xgsm.ioc.entity;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
@Scope("prototype")
@Lazy(true)
public class Student {
private int StuNum;
private String StuName;
private ClassRoom classRoom;
public Student() {
System.out.println("无参构造器");
}
@PostConstruct
public void init(){
System.out.println("----init-----");
}
public void setStuNum(int stuNum) {
StuNum = stuNum;
}
public void setStuName(String stuName) {
StuName = stuName;
}
public void setClassRoom(ClassRoom classRoom) {
this.classRoom = classRoom;
}
}
根据测试类,可以看到方法是在构造器之后执行的
3.5 @PreDestory
@PreDestory注解是方法注解,声明一个方法为当前类的销毁方法,在对象容器中释放之前执行,相当于bean标签中的destory-method属性,此方法没办法测试,一般使用此方法可以实现关闭数据连接等操作~
package com.xgsm.ioc.entity;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
@Component
@Scope("prototype")
@Lazy(true)
public class Student {
private int StuNum;
private String StuName;
private ClassRoom classRoom;
public Student() {
System.out.println("无参构造器");
}
@PostConstruct
public void init(){
System.out.println("----init-----");
}
public void destory(){
System.out.println("-----destory----");
}
public void setStuNum(int stuNum) {
StuNum = stuNum;
}
public void setStuName(String stuName) {
StuName = stuName;
}
public void setClassRoom(ClassRoom classRoom) {
this.classRoom = classRoom;
}
}
3.6 @Autowired
@Autowired是属性注解,声明当前属性自动装配,默认是bytype,默认必须(如果没有找到类型与属性类型匹配的bean则会抛出异常);@Autowired(require=false)设置当前自动装配是否为必须,默认是必须
实体类-@Autowired自动装配 | 测试类 |
package com.xgsm.ioc.entity; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Lazy; import org.springframework.context.annotation.Scope; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; @Component @Scope("prototype") @Lazy(true) public class Student { private int StuNum; private String StuName; private ClassRoom classRoom; public Student() { System.out.println("无参构造器"); } @PostConstruct public void init(){ System.out.println("----init-----"); } public void destory(){ System.out.println("-----destory----"); } public void setStuNum(int stuNum) { StuNum = stuNum; } public void setStuName(String stuName) { StuName = stuName; } @Autowired public void setClassRoom(ClassRoom classRoom) { this.classRoom = classRoom; } public ClassRoom getClassRoom() { return classRoom; } } | package com.xgsm.ioc.Test; import com.xgsm.ioc.entity.Student; import org.springframework.context.support.ClassPathXmlApplicationContext; public class test { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("ApplicationContext.xml"); Student student = (Student) context.getBean("student"); System.out.println(student.getClassRoom()); } } |
当不把ClassRoom交给spring容器管理时,此时对setClassRoom()方法使用自动装配,会报错,因为通过类型匹配不到ClassRoom,就会派出异常
异常处理,只需要将实体类ClassRoom交给spring容器管理即可,在ClassRoom实体类中使用@Component注解,即问题可解~
package com.xgsm.ioc.entity;
import org.springframework.stereotype.Component;
@Component
public class ClassRoom {
}
测试类执行结果,打印Student类中的classRoom的值
除此之前,使用@Autowired自动装配我们还可以在set方法中使用@Qualifier("id名"),来通过“id”名进行查找自动装配,如果找不到则会抛异常,所以需要在ClassRoom实体类中,给@Component(“”)赋值
package com.xgsm.ioc.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
/**
* Description: Spring-Ioc-demo02
* Created by WuHuaSen .
* Created Date: 2022/4/13 16:31
* Version: V1.0
*/
@Component
@Scope("prototype")
@Lazy(true)
public class Student {
private int StuNum;
private String StuName;
private ClassRoom classRoom;
public Student() {
System.out.println("无参构造器");
}
@PostConstruct
public void init(){
System.out.println("----init-----");
}
public void destory(){
System.out.println("-----destory----");
}
public void setStuNum(int stuNum) {
StuNum = stuNum;
}
public void setStuName(String stuName) {
StuName = stuName;
}
@Autowired
public void setClassRoom(@Qualifier("clazzroom") ClassRoom classRoom) {
this.classRoom = classRoom;
}
public ClassRoom getClassRoom() {
return classRoom;
}
}
3.6 @Resource
@Resource是属性注解,也用于声明属性的自动装配,默认装配方式为byName,如果根据byName没有找到对应的Bean,则继续通过ByType寻找对应的Bean,或者根据Bytype找到的bean不止一个,那么也会抛出异常
package com.xgsm.ioc.entity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
/**
* Description: Spring-Ioc-demo02
* Created by WuHuaSen .
* Created Date: 2022/4/13 16:31
* Version: V1.0
*/
@Component
@Scope("prototype")
@Lazy(true)
public class Student {
private int StuNum;
private String StuName;
private ClassRoom classRoom;
public Student() {
System.out.println("无参构造器");
}
@PostConstruct
public void init(){
System.out.println("----init-----");
}
public void destory(){
System.out.println("-----destory----");
}
public void setStuNum(int stuNum) {
StuNum = stuNum;
}
public void setStuName(String stuName) {
StuName = stuName;
}
@Resource
public void setClassRoom(ClassRoom classRoom) {
this.classRoom = classRoom;
}
public ClassRoom getClassRoom() {
return classRoom;
}
}
四、总结:
用了注解之后,就不需要在xml文件中配置了,Spring提供了几个辅助类会自动扫描和装配这些Bean。所以使用注解能大大减少xml文件的体积,Spring启动时会根据配置去扫描某些包里的类,得到类或方法上的注解,不同的注解会进行不同的操作。
优点:
1、节省配置,减少配置文件大小
2、编译时即可查看正确与否,提高效率
缺点:
1、增加了程序的耦合性,因为注解保存在class文件中,而且比较分散若要对配置进行修改需要重新编译