关于Spring-IOC,如果有错误,欢迎指正。
Spring-IOC
Spring框架包含众多模块,如Web Servlet、Data Access、Core Container等,其中在Core Container(核心容器)模块中的Core核心模块,提供了Spring框架的基本组成部分,包括了IOC和DI功能。
上图的SpEl指的是Expression Language 模块:是运行时查询和操作对象图的强大的表达式语言。
IOC和AOP作为Spring框架的核心,我们也要重点去学习。
一、什么是IOC
IOC(Inversion of Control)是控制反转是意思,是一种面向对象编程的设计思想。IOC可以把对象的创建和对象之间的调用过程,交给Spring进行管理,从而降低对象之间的耦合度。
二、IOC的底层原理
IOC的底层原理:xml解析、工厂模式、反射。
IOC实现原理:在工厂模式的基础上,利用xml配置文件,配置创建的对象,然后在工厂类的返回userDao对象的方法中,通过对xml解析获得 userDao 的类路径,再通过反射创建对象,最后返回对象。
这种IOC的过程在工厂模式的基础上进一步降低了耦合度。
三、IOC(接口)
1、IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
2、Spring提供IOC容器实现两种方式:
(1)BeanFactory:IOC容器基本实现,是Spring内部使用的接口,不供开发人员使用。
(2)ApplicationContext:BeanFactory接口的子接口,有更强大的功能。
BeanFactory与ApplicationContext的区别:
BeanFactory在加载配置文件时不会去创建对象,在(获取)使用对象的时候才会创建对象。
ApplicationContext在加载配置文件的时候就把配置文件对象进行创建。
ApplicationContext虽然会加长项目的启动时间,但在web项目运行时,可以减少加载时间和内存消耗,适合Web开发,推荐使用(耗时耗内存的都在项目启动的时候进行处理更加合适)。
3、ApplicationContext接口实现类:
(1)ClassPathXmlApplicationContext:
在new的时候需要指定类的路径(src下)
(2)FileSystemXmlApplicationContext
盘的路径(例如:C://file.xml)
4、BeanFactory
ConfigurableApplicationContext:该子接口中可以包括相关的扩展功能
四、IOC操作
在进行ioc操作之前先在我们的项目中引入spring的基本jar包(核心容器和日志)
在项目中导入这5个jar包
bean管理:
什么是bean管理(两个操作):
1、spring创建对象
2、spring属性注入
bean管理操作(基于xml):
基于xml创建对象:
在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建
bean常用属性:
(1)id: 唯一标识
(2)class: 类全路径(包类路径)
(3)name: 和id一样,但是可以增加 / 等特殊符号。
创建对象的时候也是默认执行无参构造方法,完成对象创建
没有无参构造会报错:
xml:
User:
基于xm属性注入:
DI:依赖注入,就是注入属性。
1、set方法进行注入:
(1)创建类,定义属性和对应set方法
public class User {
private int id ;
private String name;
public void setId(int id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
}
(2)在spring配置文件中配置对象的创建,配置属性注入
在property标签中注入
<bean id="user" class="com.songzhi.spring.User">
<!-- name的值为类中的属性名,value的值为属性名对应的值(向属性注入的值)-->
<property name="id" value="123"></property>
<property name="name" value="刀哥"></property>
</bean>
在User类中加入toString方法:
public void toUserString(){
System.out.println("UserId = "+id);
System.out.println("UserName = "+name);
}
测试类进行测试:
@Test
public void testAdd(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user",User.class);
user.toUserString();
}
输出效果:
2、有参构造进行注入:
(1)创建类,定义属性,创建属性对应有参构造方法:
public class User {
private int id ;
private String name;
User(int id ,String name){
this.id=id;
this.name=name;
}
public void toUserString(){
System.out.println("UserId = "+id);
System.out.println("UserName = "+name);
}
}
(2)在spring配置文件中进行配置
<bean id="user" class="com.songzhi.spring.User">
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="name" value="小明"></constructor-arg>
</bean>
测试类与上面set方法测试类相同,输出结果:toset
3、p名称空间注入:
使用p名称空间注入,可以简化基于xml配置方式
(1)添加p名称空间在配置文件中:
<?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:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
(2)进行属性注入,在bean标签里面进行操作:
<bean id="user" class="com.songzhi.spring.User"
p:id="2" p:name="小红">
</bean>
注意:这种方式底层用的是set方法进行注入!!!
这次使用上面set方法进行注入的类,测试类也是用set方法进行注入的测试类。toset
输出结果:
xml注入其他类型属性:
1、字面量:
(1)NULL值
对user的name属性注入null:
<bean id="user" class="com.songzhi.spring.User">
<property name="id" value="0"></property>
<property name="name">
<null/>
</property>
</bean>
测试类和user类与上面set方法注入相同toset
输入结果:
(2)属性值包含特殊符号:
如果赋值中含有特殊符号有两种方式进行属性注入:
第一种:使用转义字符(<
>
)=>(< >)
<bean id="user" class="com.songzhi.spring.User">
<property name="id" value="0"></property>
<property name="name" value="<>">
</property>
</bean>
测试类和user类与上面set方法注入相同toset
输出结果:
第二种:把带特殊符号内容写到CDATA当中去:(<![CDATA[特殊符号内容]]>
)
<bean id="user" class="com.songzhi.spring.User">
<property name="id" value="0"></property>
<property name="name">
<value><![CDATA[<&*()>]]></value>
</property>
</bean>
测试类和user类与上面set方法注入相同toset
输出结果:
2、注入属性-外部bean
如下图结构创建类和接口:
其中,UserDaoImpl类:
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("UserDaoImpl update ......");
}
}
UserDao类:
public interface UserDao {
void update();
}
UserService类:
在service类中调用dao里面的方法。
public class UserService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
System.out.println("service add ......");
userDao.update();
}
}
配置文件:
<bean id="userService" class="com.songzhi.spring.service.UserService">
<property name="userDao" ref="userDaoImpl"></property>
</bean>
<bean id="userDaoImpl" class="com.songzhi.spring.dao.impl.UserDaoImpl"></bean>
测试类:
@Test
public void testAdd(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
输出结果:
这种spring的方式可以实现在Service的add方法中调用daoimpl中的方法。
原始的做法可以在add中加入:
UserDao userDao = new UserDaoImpl();
userDao.update();
这样利用多态也可以做到在service的方法中调用接口实现类的方法。
3、注入属性-内部bean:
(1)现在有一对多的关系:
部门和员工,一个部门有多个员工,一个员工属于一个部门。
一:部门,多:员工
(2)在实体类中表示一对多的关系:
/**
* 部门类
*/
public class Dept {
private String DName;
public void setDName(String DName) {
this.DName = DName;
}
@Override
public String toString() {
return "Dept{" +
"DName='" + DName + '\'' +
'}';
}
}
/**
* 员工类
*/
public class Emp {
//姓名
private String EName;
//性别
private String gender;
//部门
private Dept dept;
public void setEName(String EName) {
this.EName = EName;
}
public void setGender(String gender) {
this.gender = gender;
}
public void setDept(Dept dept) {
this.dept = dept;
}
@Override
public String toString() {
return "Emp{" +
"EName='" + EName + '\'' +
", gender='" + gender + '\'' +
", dept=" + dept.toString() +
'}';
}
}
(3)在spring配置文件中进行配置:
<bean id="emp" class="com.songzhi.spring.entity.Emp">
<property name="EName" value="Li"></property>
<property name="gender" value="女"></property>
<property name="dept">
<bean id="dept" class="com.songzhi.spring.entity.Dept">
<property name="DName" value="技术部"></property>
</bean>
</property>
</bean>
测试类:
@Test
public void testOne(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Emp emp = context.getBean("emp",Emp.class);
System.out.println(emp.toString());
}
输出结果:
4、注入属性-级联赋值:
第一种写法:外部bean:
<bean id="emp" class="com.songzhi.spring.entity.Emp">
<property name="EName" value="wan"></property>
<property name="gender" value="男"></property>
<!--级联赋值-->
<property name="dept" ref="Dept"></property>
</bean>
<bean id="Dept" class="com.songzhi.spring.entity.Dept">
<property name="DName" value="安保部"></property>
</bean>
其他部分与上面一样:toOthers
输出结果:
第二种写法:使用对象.属性的方式
这种方式会调用类中的get方法,所以我们要先在Emp类中生成get方法
public Dept getDept() {
return dept;
}
xml:
<bean id="emp" class="com.songzhi.spring.entity.Emp">
<property name="EName" value="lin"></property>
<property name="gender" value="男"></property>
<property name="dept" ref="dept"></property>
<property name="dept.DName" value="财务部"></property>
</bean>
<bean id="dept" class="com.songzhi.spring.entity.Dept">
<property name="DName" value="安保部"></property>
</bean>
输出内容:
5、注入集合属性:
注入包括:数组类型,list集合类型,map集合类型
(1)创建类,定义数组、list、map、set,生成对应的set方法
public class Stu {
//数组
private String[] courses;
//集合
//list
private List<String> lists;
//map
private Map<String,String> maps;
//set
private Set<String> sets;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setLists(List<String> lists) {
this.lists = lists;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
public void setSets(Set<String> sets) {
this.sets = sets;
}
@Override
public String toString() {
return "Stu{" +
"courses=" + Arrays.toString(courses) +
", lists=" + lists +
", maps=" + maps +
", sets=" + sets +
'}';
}
}
(2)在spring配置文件中进行配置
数组类型可以使用list标签或者array标签进行注入。
<bean id="stu" class="com.songzhi.spring.entity.Stu">
<!--注入数组-->
<property name="courses">
<array>
<value>数学</value>
<value>英语</value>
</array>
</property>
<!--注入list-->
<property name="lists">
<list>
<value>60分</value>
<value>90分</value>
</list>
</property>
<!--注入map-->
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="Python" value="python"></entry>
</map>
</property>
<!--注入set-->
<property name="sets">
<set>
<value>体育部长</value>
<value>学生会长</value>
</set>
</property>
</bean>
(3)测试类:
@Test
public void testTwo(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Stu stu =context.getBean("stu",Stu.class);
System.out.println(stu.toString());
}
输出结果:
细节:
在list集合中放入对象类型:
实体类:
public class Teacher {
private List<Course> courses;
public void setCourses(List<Course> courses) {
this.courses = courses;
}
public void toTeacherString(){
for (Course course : courses) {
System.out.println(course.toString());
}
}
}
public class Course {
private String cname;
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Course{" +
"cname='" + cname + '\'' +
'}';
}
}
配置文件:
<bean id="teacher" class="com.songzhi.spring.entity.Teacher">
<property name="courses">
<list>
<ref bean="course1"/>
<ref bean="course2"/>
</list>
</property>
</bean>
<bean id="course1" class="com.songzhi.spring.entity.Course">
<property name="cname" value="JAVA"></property>
</bean>
<bean id="course2" class="com.songzhi.spring.entity.Course">
<property name="cname" value="TypeScript"></property>
</bean>
test类:
@Test
public void testThree(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
Teacher teacher = context.getBean("teacher",Teacher.class);
teacher.toTeacherString();
}
注意:
内部的property只能在当前bean中使用,需要把里面的property分别抽取出来,作为公共部分来使用。
把集合注入部分提取出来:
(1)在spring配置文件中引入名称空间util
新建一个bean.xml,引入名称空间util
<?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:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-util.xsd">
</beans>
(2)使用util标签完成list集合注入提取
<bean id="stu" class="com.songzhi.spring.entity.Stu">
<!--注入数组-->
<property name="courses" ref="course"/>
<!--注入list-->
<property name="lists" ref="list"/>
<!--注入map-->
<property name="maps" ref="map"/>
<!--注入set-->
<property name="sets" ref="set"/>
</bean>
<util:list id="course">
<value>数学</value>
<value>英语</value>
</util:list>
<util:list id="list">
<value>60分</value>
<value>90分</value>
</util:list>
<util:map id="map">
<entry key="JAVA" value="java"></entry>
<entry key="Python" value="python"></entry>
</util:map>
<util:set id="set">
<value>体育部长</value>
<value>学生会长</value>
</util:set>
这样的话就可以在公共使用值了
6、FactoryBean
FactoryBean是Spring容器提供的一种可以扩展容器对象实例化逻辑的接口,与BeanFactory不同,这里的Bean是生产对象的工厂。
应用场景:
FactoryBean 通常是用来创建比较复杂的bean,一般的bean 直接用xml配置即可,但如果一个bean的创建过程中涉及到很多其他的bean 和复杂的逻辑,用xml配置比较困难,这时可以考虑用FactoryBean。
Spring中有两种bean:普通bean和工厂bean
普通bean:
在配置文件中定义bean类型就是返回类型
工厂Bean:
在配置文件中定义bean类型可以和返回类型不一样
工厂bean中的三个方法:
public String getObject() throws Exception
:该方法返回该FactoryBean“生产”的对象。我们需要实现该方法以给出自己对象实例化逻辑
public Class<?> getObjectType()
:该方法仅返回getObject()方法所返回的对象的类型。如果预先无法确定,则返回null
public boolean isSingleton()
:该方法返回结果用于表明,getObject()“生产”的对象是否要以singleton(单例)形式存于容器中。如果以singleton形式存在,则返回true,否则返回false
第一步:创建类,让这个类作为工厂Bean,实现接口FactoryBean
public class MyBean implements FactoryBean<Course> {
@Override
public Course getObject() throws Exception {
return null;
}
@Override
public Class<?> getObjectType() {
return null;
}
}
在getObject方法中可以定义返回bean
第二步:实现接口里面的方法,在实现的方法中定义返回的bean类型:
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("abc");
return course;
}
xml:
<bean id="myBean" class="com.songzhi.spring.Bean.MyBean">
</bean>
测试类:
@Test
public void testFour(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Course course = context.getBean("myBean",Course.class);
System.out.println(course.toString());
}
实体类:
public class Course {
private String cname;
public void setCname(String cname) {
this.cname = cname;
}
@Override
public String toString() {
return "Course{" +
"cname='" + cname + '\'' +
'}';
}
}
输出结果:
Bean的作用域以及生命周期:
作用域:
在Spring里面,设置bean实例是单实例还是多实例:
Spring中,默认情况下bean是单实例对象:
@Test
public void test1(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Course course1 = context.getBean("course",Course.class);
Course course2 = context.getBean("course",Course.class);
System.out.println(course1);
System.out.println(course2);
}
public class Course {
private String cname;
public void setCname(String cname) {
this.cname = cname;
}
}
<bean id="course" class="com.songzhi.spring.entity.Course">
<property name="cname" value="123"/>
</bean>
输出结果:
由此可见默认是单实例模式,两个对象输出的地址相同。
设置单实例和多实例的方法:
在spring配置文件bean标签里面有属性(scope)用于 设置单实例还是多实例:
prototype是多实例,singleton是单实例。
在bean标签中设置多实例:
<bean id="course" class="com.songzhi.spring.entity.Course" scope="prototype">
<property name="cname" value="123"/>
</bean>
设置多实例之后的输出:
singleton和prototype的区别:
第一个singleton是单实例prototype是多实例;
第二个设置scope是singleton是时候,加载spring配置文件的时候就会创建单实例的对象;
设置scope是prototype的时候,不是在加载spring配置文件的时候创建对象,在调用getBean方法的时候创建多实例对象;
下面两个类型只适用于web程序:
request:表示一次请求,每次创建对象会放进request对象当中。
session:一次会话,每次创建对象会放进session对象当中。
关于scope其他类型的详细介绍:
spring中的scope详解 - 山高我为峰 - 博客园 (cnblogs.com)
bean生命周期(7步):
从对象创建到对象销毁的过程叫做生命周期(创建、注入、初始化、使用、销毁)
(1)通过构造器创建bean实例(无参数构造):
public class Life {
public Life(){
System.out.println("第一步:执行无参构造创建bean实例。");
}
}
(2)为bean 的属性设置值,和对其他bean 的引用(调用set方法)
public class Life {
private String LifeName;
public Life(){
System.out.println("第一步:执行无参构造创建bean实例。");
}
public void setLifeName(String lifeName) {
LifeName = lifeName;
System.out.println("第二步:调用set方法设置属性值。");
}
}
(3)调用bean 的初始化的方法(需要进行配置初始化的方法)
在life中定义销毁的方法:
public void initMethod(){
System.out.println("第三步:执行初始化的方法。");
}
在xml中引入:
<bean id="life" class="com.songzhi.spring.Bean.Life" init-method="initMethod">
<property name="lifeName" value="lifeName的value"></property>
</bean>
(4)bean可以使用了(对象获取到了)
@Test
public void testLife(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
Life life = context.getBean("life",Life.class);
System.out.println("第四步:获取创建bean实例化对象");
System.out.println("使用life中:"+life);
//手动销毁bean实例
((ClassPathXmlApplicationContext)context).close();
}
(5)当容器关闭的时候,调用bean中销毁的方法(需要进行配置销毁的方法)
手动创建销毁的方法:
public void destroyMethod(){
System.out.println("第五步:执行销毁的方法。");
}
xml中引入:
<bean id="life" class="com.songzhi.spring.Bean.Life" init-method="initMethod" destroy-method="destroyMethod">
<property name="lifeName" value="lifeName的value"></property>
</bean>
在测试类中手动销毁bean实例:
//手动销毁bean实例
((ClassPathXmlApplicationContext)context).close();
测试结果:
上面一共是5步,算上下面的后置处理器是七步:
bean的后置处理器:把bean实例传递bean后置处理器的方法,此方法在初始化分别前后,有两个方法
一个是postProcessBeforeIntialization
一个是postProcessAfterIntialization
后置处理器:
创建MyBeanPost类:
public class MyBeanPost implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行的方法。");
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行的方法。");
return bean;
}
}
在xml中配置后置处理器:
<bean id="myBeanPost" class="com.songzhi.spring.Bean.MyBeanPost"></bean>
输出结果:
第一步:执行无参构造创建bean实例。
第二步:调用set方法设置属性值。
第三步:在初始化之前执行的方法。
第四步:执行初始化的方法。
第五步:在初始化之后执行的方法。
第六步:获取创建bean实例化对象
使用bean
第七步:执行销毁的方法。
xml方式的自动装配:
什么是自动装配:
根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
基于xml文件的自动装配:byType(类型),byName(名称), constructor(构造函数)
自动装配过程:
根据属性名称自动注入(byName):
<bean id="emp" class="com.songzhi.spring.entity.Emp" autowire="byName"></bean>
<bean id="dept" class="com.songzhi.spring.entity.Dept" ></bean>
设置属性为byName,那么spring会根据class属性找到对应实体类,然后查询实体类中所有的set方法的名字,根据set方法后面的名字(比如setName方法后面的名字就是Name)再到配置文件中寻找一个与该名字相同id的bean(id=“Name”),注入进来。
根据属性类型进行自动注入(byType):
<bean id="emp" class="com.songzhi.spring.entity.Emp" autowire="byType"></bean>
<bean id="dept" class="com.songzhi.spring.entity.Dept" ></bean>
设置autowire属性为byType,那么Spring会自动寻找一个与该属性类型相同的Bean(class值中"."的最后一个,例如class="com.songzhi.spring.entity.Emp"的类型就是Emp),注入进来。
*注意:使用byType这种方式,必须保证配置文件中所有bean的class属性的值是唯一的,否则就会报错。(就是xml中的bean标签的class的值必须都不一样)。
外部属性文件:
直接配置数据库信息:
引入德鲁伊jar包:
配置德鲁伊连接池;
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/jdbctext"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
引入外部属性文件配置数据库连接池:
(1)创建外部属性文件properties格式文件,数据库连接信息
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/jdbctext
prop.username=root
prop.password=123456
等号前面的名字可以随便写,但为了防止名称冲突使用prop点的方式命名
(2)把外部的properties文件引入到spring配置文件中来:
引入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
">
在spring配置文件中使用标签引入外部配置文件
<!-- 在spring配置文件中使用标签引入外部配置文件-->
<context:property-placeholder location="classpath:Application.properties"/>
<!-- 配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${prop.driverClass}"/>
<property name="url" value="${prop.url}"/>
<property name="username" value="${prop.username}"/>
<property name="password" value="${prop.password}"/>
</bean>
IOC(bean管理)基于注解:
1、什么是注解:
(1)注解是代码特殊标记
格式:@注解名( 属性名=属性值,属性名=属性值,。。。)
(2)注解在什么什么时候用:
类上面、方法上面、属性上面
(3)使用注解的目的
简化xml配置
2、Spring针对Bean管理中创建对象提供注解:
- @Component
- 普通注解,创建对象
- @Service
- 用在业务逻辑层/Service层上
- @Controller
- 用在Web层上
- @Repository
- 用在Dao层或Mapper上
- 上面四个注解功能是一样的,都可以用来创建bean
3、基于注解方式实现对象的创建:
1、引入依赖:
2、开启组件扫描:
<?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:component-scan base-package="com.songzhi"/>
</beans>
3、创建类,在类上面添加创建对象注解:
/**
* 在注解里面value属性值可以省略不写
* 默认是类名称,首字母小写
*/
@Component(value = "manService")
public class ManService {
public void add(){
System.out.println("ManService add......");
}
}
4、开启组件扫描细节配置:
1、
<!-- use-default-filters="false" 表示现在不使用默认 filter,自己配置 filter-->
<!-- context:include-filter ,设置扫描哪些内容-->
<context:component-scan base-package="com.songzhi" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
2、
<!-- 下面配置扫描包所有内容-->
<!-- context:exclude-filter: 设置哪些内容不进行扫瞄-->
<context:component-scan base-package="com.songzhi">
<context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
</context:component-scan>
5、基于注解方式实现属性注入:
@AutoWired
根据属性类型自动注入
1、把service和dao对象创建,在service和dao类添加创建对象注解
2、在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解
<context:component-scan base-package="com.songzhi" use-default-filters="false">
<context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
<context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
</context:component-scan>
@Component
public interface UserDao {
void update();
}
@Service
public class UserService {
@Autowired
private UserDao userDao;
public void add(){
System.out.println("service add ......");
userDao.update();
}
}
@Qualifier
根据属性名称注入
这个注解的使用要和上面的Autowired一起使用
@Service
public class UserService {
@Autowired//根据类型进行注入
@Qualifier(value = "userDaoImpl")//根据名称进行注入
private UserDao userDao;
public void add(){
System.out.println("service add ......");
userDao.update();
}
}
@Component
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("UserDaoImpl update ......");
}
}
@Resource(Javax)
根据属性类型和属性名称注入
只写resource默认根据类型进行注入
<context:include-filter type="annotation" expression="org.springframework.stereotype.Repository"/>
// @Resource//根据类型进行注入
@Resource(name = "userDao")//根据名称进行注入
private UserDao userDao
@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("UserDaoImpl update ......");
}
}
@Repository(value=“userDao”)注解是告诉Spring,让Spring创建一个名字叫“userDao”的UserDaoImpl实例。
当Service需要使用Spring创建的名字叫“userDao”的UserDaoImpl实例时,就可以使用@Resource(name = “userDao”)注解告诉Spring,Spring把创建好的userDao注入给Service即可。
@Repository原文链接:https://blog.youkuaiyun.com/weixin_39426138/article/details/77679912
Value
注入普通类型属性
@Value(value = "abc")
private String name;
6、完全注解开发:
(1)创建配置类,替代xml配置文件
@Configuration //作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.songzhi"})
public class SpringConfig {
}
(2)编写测试类
@Test
public void test6(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService",UserService.class);
System.out.println(userService);
userService.add();
}
其他类:
@Service
public class UserService {
// @Autowired//根据类型进行注入
// @Qualifier(value = "userDaoImpl")//根据名称进行注入
// @Resource//根据类型进行注入
@Resource(name = "userDao")//根据名称进行注入
private UserDao userDao;
@Value(value = "abc")
private String name;
public void add(){
System.out.println("注入的name的值为:"+name);
System.out.println("service add ......");
userDao.update();
}
}
@Component
public interface UserDao {
void update();
}
@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("UserDaoImpl update ......");
}
}
输出结果:
学习源自:尚硅谷Spring框架视频教程(spring5源码级讲解)_哔哩哔哩_bilibili
Spring官网:Spring | Home
(1)创建配置类,替代xml配置文件
@Configuration //作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.songzhi"})
public class SpringConfig {
}
(2)编写测试类
@Test
public void test6(){
ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = context.getBean("userService",UserService.class);
System.out.println(userService);
userService.add();
}
其他类:
@Service
public class UserService {
// @Autowired//根据类型进行注入
// @Qualifier(value = "userDaoImpl")//根据名称进行注入
// @Resource//根据类型进行注入
@Resource(name = "userDao")//根据名称进行注入
private UserDao userDao;
@Value(value = "abc")
private String name;
public void add(){
System.out.println("注入的name的值为:"+name);
System.out.println("service add ......");
userDao.update();
}
}
@Component
public interface UserDao {
void update();
}
@Repository(value = "userDao")
public class UserDaoImpl implements UserDao {
@Override
public void update() {
System.out.println("UserDaoImpl update ......");
}
}
输出结果:
学习源自:尚硅谷Spring框架视频教程(spring5源码级讲解)_哔哩哔哩_bilibili
Spring官网:Spring | Home