#——————————————————————————————————Spring————————————————————————————————————
##什么是Spring
1.是软件框架,就是软件的半成品,包含了很多的组件
2.其中最核心的组件是IOC 容器
3.框架是由前辈们开发的软件的半成品,它完成了一些特定的功能,或者指定了一些新的开发方式或流程
并一定解决某些传统方式开发时存在的问题(例如运行效率、安全性、开发效率等).
####1.2.Spring的作用
创建和管理对象
使用Spring可以实现解耦,解除对象之间的耦合度
##IOC容器
Spring中的IoC指的是Inversion of Control,即控制反转.在传统开发模式中,是程序员自行编写
代码来创建对象,并为对象的属性赋值,可以理解为这个创建和赋值是一种权力,当使用Spring之后,
将这个权力交给了框架,程序员不再编写相关的代码,即没有了对象的控制器,所以,称之为控制反转
控制反转是基于DI的,即Dependency Injection,表示依赖注入,具体的表现为程序员在java类
中只需要声明属性,然后,通过框架约定的方式进行配置,这些属性就会被注入值,程序员无需自行编写代码
为这些属性赋值。
Spring通过DI实现了IoC,即IoC是希望实现的目标,而DI是实现该目标时使用的手段.
IOC控制反转
1.由代码自己控制对象的创建,称为:主动控制
2.由一个组件容器管理对象,应用从容器中获得对象,称为:控制反转
由Spring容器创建并管理对象,称为:控制反转
####1.3. Spring AOP
项目结尾再讲。
####2. Spring中的注解
####2.1.通用注解
先创建cn.tedu.spring.UserDao类。
在类之前添加@Component注解
然后,需要在Spring的配置文件中开启组件扫描:
<context:component-scan base-package=“cn.can.spring”></context:component-scan>
最后,执行单元测试:
public class TestCase {
@Test
public void simpleTest() {
//1.加载Spring配置,获取Spring容器
ClassPathXmlApplicationContext ac =
new ClassPathXmlApplicationContext(“spring.xml”);
//2.从Spring容器中获取对象
UserDao userdao = ac.getBean(“userDao”,UserDao.class);
//3.测试使用对象
System.out.println(userdao);
//4.释放资源
ac.close();
}
}
以上就已经完成了相当于的配置。
关于组件扫描
在组件扫描配置中,配置的属性名是base-package
,表示扫描的“根包“,假设配置为cn.tedu.spring
,则某个类在cn.tedu.spring.dap
包中,也会被扫描到!一般推荐配置值尽量与当前项目中自行开发的
类相符合
关于注解的配置
当某个类在组件扫描范围之内,且添加了注解,在加载Spring配置文件时,就会创建该类的对象,
Spring容器会使用类名的首字母改为小写,作为该对象的bean id,例如类名是UserDao则bean id就
是userDao,如果类名是Person,则bean id就是person。
也可以配置注解,自定义bean id:
@Component(“dao”)
public class UserDao { …
关于其他通用注解
添加在类之前的注解有:
@Component
@Controller
@Service
@Repository
当基于MVC的理念编程时,对于不同定位的类,应该使用不同的注解,
例如某个类如果是 控制类 ,则应该添加@Controller
注解,
如果某个类是 业务类 ,则应该添加@Service
注解,
如果某个类是用于 处理持久层 的,则应该添加@Repository
注解,
而其他定位的类,且是需要由Spring管理的,都添加@Component
注解!
以上4种注解的作用是完全相同的!使用方式也是完成相同的!只有在源代码中表示的语义不同!
###2.2.————————————————————————单例@Scope(“prototype”)
由Spring管理的对象默认是单例的,如果需要是非单例对象,可以使用@Scope("prototype")
注解:
@Component
@Scope(“prototype”)
public class UserDao {
}
在类之前可以添加多个注解,且不区分先后顺序
####2.3.——————————————————————————懒加载@Lazy
由Spring管理的单例的对象,默认并不是懒加载的,而是饿汉式的单例模式.
如果需要是懒加载的,可以在类之前添加@Lazy注解:
@Repository
@Lazy
public class UserDao {
}
注意:懒加载或者饿汉式加载都是基于单例模式位前提的,所以,在测试之前,务必保证当前类是单例的!
关于
@Lazy
也可以详细配置为@Lazy(true)或@Lazy(false),但是,没有必要!
##附3:单例模式
单例模式可以保证某个事件点,某类的对象一定最多只有1个!
基本实现为:
public class King{
private static King king= new King();
private King(){
}
public static King getInstance(){
return king;
}
}
King k1 = new King();//报错
King k2 = new King();//报错
以上是饿汉式的单例模式的实现思路.另外,还有懒汉式的单例模式,它表现的核心是"不要逼不得已,不会
创建对象!"
public static King getInstance(){
if(kingnull){
sychornized(?){
//if(kingnull){
king=new King();
}
}
}
return king;
}
以上代码还存在多线程安全问题,为了解决该问题,还应该将以上代码加上sychronized
互斥锁
####2.4.——————————————————————————————生命周期
由于将对象交给Spring去创建和管理,对于程序员来说,并不知道某个类的对象是几时几分创建的,也
不知道是几时几分的销毁的!假设存在某个InputStream流对象,应该最终被销毁,即调用它的close()
方法,但是,程序员却无法确定什么时候调用这个close()方法,所以,就需要生命周期方法!
可以在初始化方法之
前添加@PostConstruct注解,
在销毁方法之前添加@PreDestroy注解:
@Repository
public class UserDao {
public UserDao() {
System.out.println(“UserDao()”);
}
@PostConstruct
public void init() {
System.out.println(“UserDao.init()”);
}
@PreDestroy
public void destroy() {
System.out.println(“UserDao.destroy()”);
}
}
初始化方法会在构造方法之后执行,销毁方法会在Spring容器销毁之前执行。
以上2个注解是Java EE中的注解,需要为项目添加Tomcat运行环境后才识别以上2个注解。
注意:由Spring管理的对象中,只有单例的对象,才有必要讨论生命周期的问题。
###附4:生命周期
通常,需要讨论生命周期的问题的,类的对象都不是由程序员进行管理的!也就是程序员在开发过程中,不会
手动的创建这些类的对象,也不会调用它们的方法.
生命周期是描述某个类的对象从创建到销毁的过程.
对象的生命周期表现为存在一系列的生命周期方法,以Servlet
为例,就由
init()
service()
destroy()
这些方法,这些方法都在特定的时候会被执行,例如当创建完某个servlet
的对象时,
就会执行init()方法
,当这个Servlet接收到请求后,就会执行serice()
方法…
讨论生命周期的重点在于: 有哪些生命周期方法,这些方法都在什么情况下被调用!从而,程序员才可以明确
将哪些代码编写在哪个方法中
####2.5.自动装配注解
autowire=“byType||byName”
————————————————————————————————
public class UserServlet{
public UserDao userDao;
public void setUserDao(UserDao userDao){
this.userDao=userDao;
}
}
2.5. 自动装配注解
为需要自动装配的对象之前添加@Autowired
注解,即可实现自动装配:
除此以外,使用@Resource
注解也可以实现相同的效果:
@Controller
public class UserServlet {
@Resource
UserDao userDao;
}
注意:使用注解的方式实现自动装配时,不需要为属性添加SET方法!
使用@Resource
时,将优先byName
,如果失败,则byType
。如果名称无法对应,仍需要按照名称来装配,可以配置@Resource
的属性:
@Resource(name=“userDao”)
UserDao ddd;
使用@Autowired
时,将优先byType
,如果找到多个类型都匹配的,则装配名称能匹配(属性名与bean id相同)的那个对象,
如果名称都匹配失败,则抛出异常,因为byType
不允许存在多个名称相同的;如果找不到类型匹配的,也会抛出异常!
在实际开发时,以上2种注解可以根据喜好随意选取。
IOC容器就是Java Bean组件容
1.用于创建管理JavaBean对象,
2.用于替代传统的工厂模式,
3.由于其提供了DI功能,可以实现组件的解耦.
##Java Bean 规范
Java类的声明规范,是一套通行的规则,Spring默认情况下建议采用JavaBean规范.
1.有包 package
2.由无参构造器
3.需要实现 序列化 接口
4.包含由 getxxx 和 setXxx 方法声明的"Bean属性"!!!
-“Bean属性"不是"对象属性”!!!
-Bean属性是指 getXxx 和 setXxx方法
-对象属性是指 在类中声明的实例变量
-一般情况下对象属性和Bean属性 同名
例子
class Student{
int age =5; //对象属性 age
int getAge(){ //Bean属性age
return age;
}
int getOld(){ //包含只读的"Bean属性" old
return age;
}
}
Spring支持位Bean对象设置别名
*
##Bean 的作用域
1.默认情况下 Spring 管理的Bean对象是"单例"的
1.在容器启动时候,创建Bean对象
2.在getBean调用时候,返回Spring 容器中的Bean对象
2.在配置文件bean标签上使用 scope属性,可以这种"多例"的Bean对象
1.<bean id=…class=… scope=“prototype”> protoype原型
2.Spring容器启动的时候不创建对象
3.每次调用getBean时,创建新对象
单例:指在一个应用软件中,对象永远唯一的现象称为"单例"
单例案例:
1.编写javaBean类
public class Foo implements Serializable{
}
2.beans.xml
<bean name="foo" class="day01.Foo"></bean>
3.测试代码
@Test
public void testSingleton() {
/*
* Spring默认情况下对象是单例的
* 多次调用getBean 方法返回的是同一个对象
*/
Foo f1 =ctx.getBean(“foo”,Foo.class);
Foo f2 =ctx.getBean(“foo”,Foo.class);
System.out.println(f1==f2); //true
}
##对象生命周期管理
1.单例对象时候
1.创建对象时候执行 init-method 属性指定的方法
2.关闭容器时候 执行destroy-method 属性指定的方法
2.多例对象时候
1.创建对象时候执行 init-method 属性指定的方法,每个对象都会调用一次init方法()
2.关闭容器时候,不会执行 destroy-method 属性指定的方法
##——————————————————————————————————工厂
工厂:封装了复杂的对象创建过程,提供了一个简单方法作为接口返回对象实例.
Java中也一样,能够创建对象的方法,称为:工厂方法
例如:
Calendar cal = Calendar.getInstance();
Spring中ClassPathXmlApplicationContext 是JavaBean的工厂,其中getBean就是Spring提供的
工厂方法.
##——————————————————————————————DI 与 解耦
工人和斧子是强依赖关系(紧耦合关系) , 缺点:工人只能使用斧子!
如果改成:工人依赖于工具,工具可以是斧子或者电锯.这就是松耦合关系.
##Spring 构造器注入
构造器注入: 就是Spring调用有参数构造器创建对象。
使用构造器参数标签,实现构造器参数注入:
<!-- 构造器参数注入 -->
Tom
Spring 可以为对象Bean注入各种类型的数据
1.为Bean对象注入 Spring类型 Bean 属性
2.为Bean对象注入 基本类型的Bean属性
3.为Bean对象注入 对象类型的Bean属性
4.注入数组
5.注入集合
使用<property>
就可以注入如上类型的Bean属性
<bean id="koo" class="day02.Koo">
<!-- 注入String类型的Bean属性 -->
<property name="name" value="Andy"></property>
<!--注入double类型的Bean属性 -->
<property name="price" value="66.66"></property>
<!-- 注入对象类型的Bean属性 -->
<property name="date" ref="now"></property>
<!-- 注入数组类型的Bean属性 -->
<property name="ary">
<array>
<value>8</value>
<value>9</value>
<value>100</value>
</array>
</property>
<!-- 注入list集合类型的Bean属性 -->
<property name="cities">
<list>
<value>帝都</value>
<value>魔都</value>
<value>雾都</value>
</list>
</property>
</bean>
<bean id="now" class="java.util.Date"></bean>
Bean 属性注入的用途
##Spring表达式
Spring 提供了 Spring表达式,在配置文件中使用Spring表达式可以读取Bean对象或者集合中的值
##自动装配
1.自动按照名字进行装配
-根据Bean属性名,在Spring容器中查找同名ID的bean对象自动注入
2.自动按照类型进行装配
##基于注解的Bean管理
1.利用Spring提供的注解声明JavaBean
2.标注在源代码上,被编译器检查.如果写错误会出现编译错误
3.标注在源代码上,可以与源代码一起管理,使用方便
4.注解采用默认大于配置的编程风格.底层采用了自动装配技术.