spring学习笔记
因为本人最近刚学习完ssm,这篇当做整理思路来用,其中有不严谨的地方还请大佬指出。
因为spring涉及的内容比较多,担心自己会坚持不下去,就每天更新一些。如果对你理解
spring有所帮助那真是最好不过了。
1. spring是什么
spring是一个轻量级的、可以集成各种优秀框架的java开发框架,其核心是控制反转(ioc)和面向切面编程 (aop)。其主要作用是降低代码之间的耦合度(ioc带来的效果),提高系统的复用率以及更灵活的进行事务管理(aop带来的效果)。
2. 控制反转是什么
控制反转是一种重要思想,传统上我们使用程序来操作对象而现在我们将权限交给容器,通过容器来完成对象的创建和使用。
控制反转就是对对象控制权的转移,从程序代码本身转移到外部容器中,通过外部容器来实现对对象的创建,属性的赋值,依赖的管理。
那什么是依赖呢?
依赖:简单点可以理解为classA类有classB类的实例,通过调用classB的方法来完成功能,即A类对B类有依赖。
spring框架就是使用依赖注入(DI)来实现IOC。
这里可以把spring容器想象成一个工厂,负者创建、管理所有的java对象,这些java对象称为bean。spring容器管理着容器中的bean之间的依赖关系(依赖注入),使用IOC实现了对象的解耦合。
1. 举个栗子(第一个)
第一步,我们在java的源目录下,创建com.zxj.dao包
先定义一个接口和该接口的实现类
public interface SomeService { void doSome(); }
public class SomeServiceImpl implements SomeService {
public SomeServiceImpl() {
super();
System.out.println("SomeServiceImpl无参数构造方法");
}
@Override
public void doSome()
{ System.out.println("====业务方法doSome()==="); } }
第二步、我们在resources资源目录下创建一个spring.xml的配置文件,命名为applicationContext。接着在里面创建一个bean,这个bean的功能就是让spring容器可以为我们创建一个我们需要的实例对象。
代码如下。
<bean id="someService" class="com.zxj.dao.SomeServiceImpl" />
这个bean标签:1、class:我们想让spring容器用这个类来创建对象,其中这个类的类路径。2、id:当spring容器创建好这个对象后,我们从外部通过getBean()来获取容器中这个bean,id就是这个bean的唯一标识,具有唯一性。
第三步、创建一个测试类,来看看效果(部分代码如下)
@Test
public void test01(){
//指定spring的配置文件,并且创建spring容器
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过id来获取容器中该id指定的对象。
SomeService someService = (SomeService)app.getBean("someService");
someService.dosome();
}
这里如果按照以前的思路,需要我们手动来new,
SomeService SomeService = new SomeServiceImpl();
就像这样,但是这里我们交给了容器来做,直接从容器中来拿已经创建好的对象,
这就是控制反转。
ApplicationContext 容器会在容器对象初始化的时候,将其中所有对象一次性装配好
(说人话就是,在容器创建初始化的时候,会读取配置文件,这里我们传入的是“applicationContext.xml”,创建好这个配置文件中我们配置的bean标签所对应的对象,并且放入容器中,id为创建对象的唯一标识,供外部调取时候使用)
效果就不贴出来了,留下思考,为什么会有两个输出语句呢?
好了通过上面这个,我们已经成功通过spring容器来创建对象了,那有了对象不赋值怎么行,接下来会从多个方法来完成对对象的赋值。
1. set注入
该方式在以后是较为常用的一种,需重点照顾。
上栗子(第二个)!!!
第一步:在java的源目录下,创建com.zxj.dao包,在该包下创建一个学生类
public class Student{
private String name;
private Integer age;
}
第二步:在resources目录下创建spring.xml的配置文件,命名为applicationContext
<bean id="studnet" class="com.zxj.dao.Student" >
//简单属性赋值
<property name="name" value="卡特琳娜" />
<property name="age" value="18" />
</bean>
第三步:创建测试类
@Test
public void test02(){
//指定spring的配置文件,并且创建spring容器
ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
//通过id来获取容器中该id指定的对象。
Student student = (Student)app.getBean("studnet");
//输出 一下看下效果
System.out.println(student);
}
这里一样不把效果贴出,好奇的自己动手看看。
上面这是简单类型的注入,在后面开发中常用的还有引入注入。
上栗子(第三个)!!!
第一步、在上面这个例子的基础上,在dao包中添加一个新类取名School,并把School类引入到Student类中
public class School{
private String name;
private String address;
}
public class Student{
private String name;
private Integer age;
//应用类
private School school;
}
第二步、在applicationContext.xml配置文件中创建一个id为studnet的bean
<bean id="school" class="com.zxj.dao.School">
<property name="name" value="洛克萨斯学院" />
<property name="address" value="洛克萨斯" />
</bean>
修改之前的id为student的bean
<bean id="studnet" class="com.zxj.dao.Student" >
//简单属性赋值
<property name="name" value="卡特琳娜" />
<property name="age" value="18" />
<property name="school" ref="school" />
</bean>
第三步、运行上面例子中的测试类,看看效果。
这样我们就可以给一个类中的应用类型赋值了。其中ref指向要应用的类型的bean,也就是我们上面新创建的名为school的bean。
除了set注入以外,还有一种名为构造器注入的方式,不过不怎么常用。上栗子(第四个)!!
第一步、在dao包下创建一个新类为Student2,并且生成一个有参的构造方法
public class Student2{
private String name;
private Integer age;
//应用类
private School school;
public stu(String myName,Integer myAge,School mySchool){
this.myName=myName;
this.myAge=myAge;
this.mySchool=mySchool;
}
}
第二步、修改applicationContext配置文件中的id为student的bean
<bean id="studnet" class="com.zxj.dao.Student" >
//简单属性赋值
<constructor-arg name="myName" value="卡特琳娜" />
<constructor-arg name="myAge" value="18" />
<constructor-arg name="mySchool" ref="school" />
</bean>
第三步、运行测试类,看看效果。这里不会贴出运行结果!!!(以后也不会,,,,)
俗话说:不会偷懒的程序猿不是好的程序猿。当遇到应用类型的时候,我们一边要给引用类型创建一个bean,一边还有修改应用该类型的bean。太累了,诶,这里前辈们也想到了,于是 “引用类型注入” 应运而生。
引用类型自动注入,有两个方法:
1、byName(顾名思义通过名字来完成注入),
2、byType(顾名思义通过类型完成注入)。
1.1、byName.
这里可以直接修改第三个栗子,修改如下
<bean id="studnet" class="com.zxj.dao.Student" autowire="byName" >
//简单属性赋值
<property name="name" value="卡特琳娜" />
<property name="age" value="18" />
//<property name="school" ref="school" />
这样修改后,spring在加载配置文件开始创建student对象的时候,会自动搜索与student类中应用类型的变量名相同的bean的id,相匹配,完成注入赋值。在第三个栗子中,我把引用类型的变量名定义成了school这样在加载配置文件的时候,spring会搜索有没有bean的id为school,有的话就会完成自动注入。
2.1byType类型注入
这里一样在第三个栗子基础上进行理解。上修改
<bean id="studnet" class="com.zxj.dao.Student" autowire="byType" >
//简单属性赋值
<property name="name" value="卡特琳娜" />
<property name="age" value="18" />
//<property name="school" ref="school" />
这里可以看到,我们只是将byName换成了byType。顺序一样是,加载配置文件,创建student对象时候,因为我们在Student类中引入的是School类的对象,所以spring会搜找bean中有没有创建好的School的对象,完成注入。
这里比较推荐byName来完成自动注入,因为如果配置文件中有多个School对象时候spring就不知道该将哪个对象注入进去,抛出异常。
在以后的开发中难免会遇到多个配置文件的情况,这里提一下如何导入外部的配置文件。
格式如下:
<import resource="calsspath:com/zxj/dao/XXXX.xml" />
重点:基于注解的DI(基于注解完成依赖注入)
1、我们首先要知道,当我们选择基于注解的时候,就不用在spring的配置文件中声明bean的实例了。
首先我们在spring配置文件中添加一个扫描器,该扫描器会扫描路径下的代码寻找注解,进一步完成相对应的操作。扫描器代码如下。
<context:componet-scan base-package="" />
base-package里面写入的是要扫描的路径具体到包就可以了。
配置好扫描器了,那么我们就可以在代码中加入注解了。
注解1:@Componet(value=""),
value的值可以理解为bean的id。具有唯一标识。value可以省略。省略后id的值为该类的类名(首字符小写)
使用位置:在类上。
好搭档:@value;位置在属性上
@Componet(value="student")
public calss Student{
@value("卡特琳娜")
private String name;
@value("18")
private Integer age
}
在注解中,同样也可以进行用byType来完成DI
注解2:@Autowired,
这里先将school类加上注解
@Compoent("mySchool")
public class School{
@value("盘龙小学")
private String name;
@value("云深不知处")
private String addre
}
修改student类
@Compoent("student")
public class Student{
@value("卡特")
private String name;
@value("18")
private Ingeter age;
@Autowried
private School school;
}
理解同xml形式的思路
说完byType,那就不得不提起byName了。
在使用@Autowried的基础上添加了@Qualifier
@Compoent("mySchool")
public class School{
@value("盘龙小学")
private String name;
@value("云深不知处")
private String addre
@Compoent("student")
public class Student{
@value("卡特")
private String name;
@value("18")
private Ingeter age;
@Autowried
@Qualifier("mySchool")
private School school;
}
细细品味一下。
同时还有基于jdk注解的@Resource使用的时候同@Autowried差不多,不过在使用byName的时候不需要使用@Qualifier,其自带name属性,
@Compoent("student")
public class Student{
@value("卡特")
private String name;
@value("18")
private Ingeter age;
@Resource(name="mySchool")
private School school;
}
来做个对比
注解优点是:
⚫ 方便
⚫ 直观
⚫ 高效(代码少,没有配置文件的书写那么复杂)。
其弊端也显而易见:以硬编码的方式写入到 Java 代码中,修改是需要重新编译代码的。
XML 方式优点是:
⚫ 配置和代码是分离的
⚫ 在 xml 中做修改,无需编译代码,只需重启服务器即可将新的配置加载。
xml 的缺点是:编写麻烦,效率低,大型项目过于复杂。