Spring框架学习笔记1:IOC介绍和使用IOC注解的方式
什么是IOC
IOC(Inversion Of Control):控制反转。
其实指的是控制权力的反转。说白了,就是将原来通过new方式创建对象的权力交给spring,通过在配置文件中配置bean标签的形式创建对象,交由spring创建对象的过程。
然而实际上,凡是可以被称之为容器的,都具有IOC这种特性,比如tomcat容器,在使用的时候可以直接获取request和response对象。为了使spring更加完善,作者又提出了新的概念。
DI(Dependency Injection):依赖注入。
定义:为组件中需要的成员变量完成赋值的过程
1.组件对象中需要哪个组件,就将其声明为成员变量并提供公开的set方法。
2.在spring配置文件中使用在对应的标签内完成属性的赋值操作。
IOC总结:控制反转,将原来手动通过new关键字创建对象的权力交给spring,由spring工厂创建对象的过程。当然spring不仅要创建对象,还要在创建对象的同时,通过DI的方式维护组件和组件之间的调用关系。
DI基本语法:
Dao层组件:
public class DeptDaoImpl implements DeptDao{
public void save(String name) {
System.out.println("姓名:"+ name);
}
}
Service层组件(调用了DAO层组件):
public class DeptServiceImpl implements DeptService {
private DeptDao deptDao;
public void setDeptDao(DeptDao deptDao) {
this.deptDao = deptDao;
}
public void save(String name) {
System.out.println("service name : "+ name);
deptDao.save(name);
}
}
spring.xml配置文件:
<bean class="di.DeptDaoImpl" id="aa"></bean>
<bean class="di.DeptServiceImpl" id="deptService">
<!--
property: 用来给组件中的属性进行赋值操作
name:用来指定给组件中的哪个属性进行赋值(也就是变量名)
ref: 用来指定对象在工厂中的唯一标识名(也就是bean的id)
-->
<property name="deptDao" ref="aa"></property>
</bean>
测试:
public class test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
DeptServiceImpl deptServiceImpl = (DeptServiceImpl) context.getBean("deptService");
deptServiceImpl.save("wuhaotian");
}
}
DI中的注入方式
SET注入(了解语法,实际中用得少)
定义:就是使用成员变量set方法的方式进行注入;
set方式的注入语法:
1.八中基本类型+String类型+日期类型的注入,使用value属性进行赋值;
<property name="age" value="25"></property>
2.注入对象|组件类型,使用ref属性进行赋值;
<property name="deptDao" ref="aa"></property>
3.注入数组类型
private String[] qqs;
private DeptDao[] deptDaos;
private Map<String,DeptDao> map;
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
public void setMap(Map<String, DeptDao> map) {
this.map = map;
}
public void setDeptDaos(DeptDao[] deptDaos) {
this.deptDaos = deptDaos;
}
public void setQqs(String[] qqs) {
this.qqs = qqs;
}
xml文件:
//注意这些都是在<bean>标签下面的东西
<property ame="qqs">
//数组使用array标签
<array>
//基本类型用value
<value>a</value>
<value>b</value>
<value>c</value>
</array>
</property>
<property name="deptDaos">
<array>
//引用类型用ref
<ref bean="aa"></ref>
<ref bean="aa"></ref>
<ref bean="aa"></ref>
</array>
</property>
<property name="map">
<map>
<!--基本类型和String直接用key,value,引用类型用key-ref,value-ref-->
<entry key="first" value-ref="aa"></entry>
</map>
</property>
<property name="properties">
<props>
<prop key="driver">com.mysql.jdbc.Driver</prop>
<prop key="url">jdbc:mysql://localhost:8080:/test</prop>
<prop key="username">root</prop>
<prop key="password">root</prop>
</props>
</property>
构造注入(了解语法,实际使用较少)
定义:就是使用类中的构造方法为类中的成员变量赋值的过程。
构造注入的语法:
1.需要哪个组件就将其声明为成员变量,并提供公开的构造方法。
2.在配置文件中对应的组件标签内部使用"< constructor-arg>"标签进行注入
private String name;
private int age;
private Date date;
public EmpDAOImpl(String name, int age, Date date) {
this.name = name;
this.age = age;
this.date = date;
}
xml配置文件
//这里多个index,从0开始记录。其他的属性(基本类型,引用类型)用法和set注入是一样的
<bean class="cdi.EmpDAOImpl" id="empDAO">
<constructor-arg index="0" name="name" value="kid"></constructor-arg>
<constructor-arg index="1" name="age" value="12"></constructor-arg>
<constructor-arg index="2" name="date" value="2020/7/11"></constructor-arg>
</bean>
自动注入
定义:就是通过在配置文件中完成类中属性的自动赋值。
注意:
1.底层使用的原理也是set注入的方式;
2.自动注入需要在对应组件标签上开启才能使用;
3.只能用于引用类型的注入,不能完成基本类型的注入;
4.注解用的是自动注入
5.自动注入在xml中看不出来组件之间的依赖关系
自动注入的语法:
1.需要哪个组件就将其声明为成员变量,并提供set方法;
2.在对应组件标签上加入autowired属性并指定自动注入的方式即可完成注入。
private StudentDAO studentDAO;
public void setStudentDAO(StudentDAO studentDAO) {
this.studentDAO = studentDAO;
}
@Override
public void save(String name) {
System.out.println("Service DAO:"+name);
studentDAO.save(name);
}
xml文件
<!--管理DAO组件-->
<bean class="sdi.StudentDAOImpl" id="studentDAO"></bean>
<!--
autowire:用来给组件中成员变量完成自动赋值的操作
byType:根据类型完成自动注入 根据成员变量类型去工厂找,找到对应类型完成赋值 找不到就不赋值
注意:如果工厂中存在多个同一类型的组件,此方法会失效
byName:根据名称完成自动注入 根据成员变量的名字去工厂找,找到对应类型完成赋值 找不到就不赋值
-->
<bean class="sdi.StudentServiceImpl" id="studentService" autowire="byType"></bean>
有关bean
bean的模式
- 工厂默认在管理对象时是使用单例模式,此时无论在工厂获取多少次始终是同一个对象;
- 如何修改成多例
<bean class="" id="" scope="singleton|prototype(多例)">
spring构造对象原理
反射+构造方法
//工厂原理 反射+无参构造
testDAO td = (testDAO)Class.forName("绝对路径.testDAOImpl").newInstance();
bean生命周期
单例对象:工厂启动时,所有的单例对象随之创建;
工厂正常关闭时(调用context.close()方法),所有单例对象随之销毁;
多例对象:每次在工厂中使用时创建,而且多例对象一旦创建,就脱离了spring的管理,所以对象的销毁是jvm来进行管理。
注解介绍
@Component:组件,理论上可以在任意的类上进行添加,在扫描的时候都会完成bean的注册
@Controller:放置在控制层,用来接收用户的请求,
@Service:放置在业务逻辑层,
@Repository:仓库,放置在数据访问层
他们都可以完成bean注册功能,但是这些规定并不是spring识别的标识
在spring程序运行的过程中,不会对这四个注解做任何区分。都会完成bean的注册功能
在实际的开发过程中,最好能分清楚,以此提高代码的可读性。
在使用注解的时候,要告诉spring从哪个包开始扫描
需要导入context命名空间
在使用注解的时候没有定义id和class,那么是如何进行识别的呢
默认是把当前类的首字母小写之后进行识别的,如果需要改变名称,那么需要在注解后面添加value属性值来完成名字的修改
扫描路径参数
<!--当定义好注解的扫描路径之后,可以做更细粒度的控制,可以选择扫描哪个注解,也可以选择不扫描哪个注解
include-filter:表示要包含扫描的注解,一般不会定义此规则,但是如果引入的第三方包中包含注解,此时就需要使用此标签来进行标识。
exclude-filter:表示要排除扫描的注解,使用较多
参数:
type:规则的类型
expression:表达式
参数:
assignable:可以指定对应的类的名称。但是表达式必须是完全限定名
annotation:按照注解来进行排除,但是表达式中必须是注解的完全限定名
regex:使用正则表达式的方式,一般不用
aspectj:使用切面的方式,一般不用
custom:使用自定义的方式,可以自己定义自己的筛选规则,一般不用
AutoWired装配方式
注意:当使用AutoWired注解的时候,自动装配的时候是根据类型实现的。
AutoWired是根据反射进行注入的。
1、如果只找到一个,则直接进行赋值,
2、如果没有找到,则直接抛出异常,
3、如果找到多个,那么会按照变量名作为id继续匹配,
@AutoWired和@Resource的区别
在使用自动装配的时候,出了可以使用@AutoWired注解之外,还可以使用@Resource注解,大家需要知道这两个注解的区别。
1、@AutoWired:是spring中提供的注解,@Resource:是jdk中定义的注解,依靠的是java的标准
2、@AutoWired默认是按照类型进行装配,默认情况下要求依赖的对象必须存在,@Resource默认是按照名字进行匹配的,同时可以指定name属性。
3、@AutoWired只适合spring框架,而@Resource扩展性更好
4、@Resource是按照名称进行装配的,而@AutoWired是按照类型进行装配的
泛型依赖注入
1、可以定义一个Base<T>类,在和Base相同的目录下定义具体的类,比如Student,Teacher,(注意:这里的Base类不要加自动注入的功能,否则可能会出错),然后根据具体传入的T,将对应的具体类型进行注入。
spring框架好处
- 使用配置文件管理java类,在生产环境中更换类的实现时不需要重新部署,修改文件即可;
- 默认使用单例模式,减少内存的占用;
- 通过依赖注入建立了类与类之间的关系,