springIOC:控制反转
普通JAVA程序运行流程:
1、HelloWorld.java
public class HelloWorld{
public void say(){
System.out.println("hello");
}
public static void main(String[] args){
HelloWorld hw = new HelloWorld();
hw.say();
}
}
2、.java ---> .class javac excute
3、把.class文件放入到JVM中
4、得到运行结果
Spring容器运行:
1、完成HelloWorld.java
2、把HelloWorld这个类以配置文件形式放入到容器中
3、启动Spring容器
4、利用Spring的API把HelloWorld这个对象拿出来
5、HelloWorld.say()完成方法的调用
说明:创建HelloWorld这个类是由Spring容器完成,Spring容器就相当于生活中的电饭煲,而类就像是电饭煲中的米粒,对象就像是电饭煲中的饭粒。
Spring做了创建对象这个动作,因此"反转"一次的含义为Spring自动把类转换为现实中的对象,所以叫“控制反转”。
<!--把HelloWorld这个类纳入Spring容器中,通过在applicationContext.xml配置文件中创建bean对象,bean规范写法为:
id为bean的唯一标识,类的第一个字母变为小写,其余不变;
class为类的全名!-->
<bean id="helloworld" class="***.***.Hellworld"></bean>
启动Spring容器:
public class IOCTest{
/**
*创建Spring容器就相当于启动Spring容器
*Spring做的其中的一个工作就是创建对象
*/
@Test
public void testHelloWorld(){
ApplicationContext context
= new ClassPathXmlApplicationContext("applicationContext");
HelloWorld helloWorld = context.getBean("helloWorld");
helloWorld.say();
}
}
别名
<beans>
<alias name="person" alias="p"/><!--name引用的是已经创建的bean-name,alias则是写不同于bean-name的名字,name的数量不限,相对于一个人的绰号不限-->
<bean name="person" class="cn.itcast.aliasspring.Person"/>
</beans>
通过这样的配置,可以达到在一个地方命名,在多个地方使用不同的名字的效果。
Java创建对象有两种方式:1、new 2、反射机制
Bean创建对象方法有三种:1、构造函数 2、静态工厂 3、实例工厂
springIOC总结:
* spring容器中的bean创建
* 三种方案 面试题
* 利用默认的构造函数
* 利用静态工厂方法
* 利用实例工厂方法
* 创建对象的时机
* 默认情况下,在spring启动的时候,创建纳入spring容器中所有的bean
在spring容器启动的时候,可以检查错误
但是如果bean的属性中有数据,会过早的加载到内存中,所以如果bean中有数据
应该把数据的对象的声明放在方法中
* 如果在spring的配置文件中,有lazy-init为true,则context.getBean("beanId")时才要创建对象
缺点:在spring容器启动的时候,是检验不出错误的
* 对象的作用域
* 在配置文件中,scope为
"singleton"
* 默认值
* spring产生的bean只有一个实例
* 处于单例模式的bean的创建、初始化、销毁都是受spring容器管理的
* 在容器关闭的时候执行销毁工作
"prototype"
* 多例
* spring容器负责该bean的创建、初始化,但是销毁工作程序员做
* 无论该bean的lazy-init为什么值,都在context.getBean时创建对象
* 如果该bean中有资源对象,手动关闭
* init和destroy方法
init在构造器执行完毕之后执行
destroy方法在spring关闭的时候执行
DI-Dependency Injection 依赖注入
public class Person{
private Long pid;
private String pname;
//调用set方法给属性赋值
public void setPname(String pname){
this.pname = pname;
}
//利用构造器可以给属性赋值
public Person(String pname){
this.pname = pname;
}
DI可以翻译为怎样为这些类型赋值
public class Person{
//基本数据类型
private String s;
private Long age;
//引用数据类型
private Student s;
private List<Student>;//list类型
private Set<Student>://set类型
private Map
private Properties property;//属性文件类型
}
DI依赖注入小总结:
* 依赖注入可以翻译为怎样为对象赋值
* 依赖注入主要有两种种途径
|--使用构造器注入
|--通过参数顺序注入
<constructor-arg index="0">
<value>张三</value>
</constructor-arg>
<constructor-arg index="1">
<value>56</value>
</constructor-arg>
|--通过参数类型注入
<constructor-arg type="java.lang.Integer">
<value>56</value>
</constructor-arg>
<constructor-arg type="java.lang.String">
<value>张三</value>
</constructor-arg>
|--使用属性setting方法注入,要数据类型装备
|--装配基本数据类型
<bean id="personService" class="****.PersonServiceImpl">
<!-- 基本类型,string类型 -->
<property name="age" value="20"></property>
<property name="name" value="张无忌"></property> </bean>
<bean id="person" class="com.itcast.bean.Person" />
<bean id="personService" class="com.itcast.bean.impl.PersonServiceImpl">
<property name="person" ref<!--引用其他Bean字段-->="person" />
</bean>
|--装配引用数据类型
|--装配list集合
<property name="lists">
<list>
<value>list1</value>
<value>list2</value>
<ref bean="person"/>
</list>
</property>
|--装配set集合
<property name ="sets">
<set>
<value>set1</value>
<value>set2</value>
<ref bean="person"/>
</set>
</property>
|--装配map集合
<property name="maps">
<map>
<entry key="01">
<value> map01</value>
</entry>
<entry key="02">
<value>map02</value>
</entry>
</map>
</property>
|--装配Properties
<property name="props">
<props>
<prop key="01">prop1</prop>
<prop key="02">prop2</prop>
</props>
</property>
注解:
* 用来标识的
* 注解是用来标注类里的东西
* 注解不能单独存在,只能依附于类中的结构
* jdk中经常用的几种注解:
@Target
ElementType
TYPE 类和接口
FIELD 属性
METHOD 方法
PACKAGE 包
PARAMETER 方法中的参数
CONSTRUCTOR 构造器
ANNOTATION_TYPE 注解类型
用于说明这个注解所标注的注解用在哪些地方
@Documented
是否出现在帮助文档
@Retention 作用范围
SOURCE 源代码
CLASS 源代码和class文件
RUNTIME 源代码、class文件、运行时
* 自定义注解
* 一个自定义注解必须有
@Target 说明这个注解标注在哪个部位
@Retention 说明注解的作用范围
* @interface 说明是一个注解类
* 注解类中可以有属性
String value();
* 注解解析器
用来解析标注在类上的注解
注入步骤:
A、在配置文件中,引入context命名空间
<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-2.5.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd">
B、在配置文件中加入context:annotation-config标签
<context:annotation-config/>
这个配置隐式注册了多个对注释进行解析处理的处理器
AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,
PersistenceAnnotationBeanPostProcessor,RequiredAnnotationBeanPostProcessor
注: @Resource注解在spring安装目录的libj2eecommon-annotations.jar
C、创建要扫描注解的Bean对象
工作原理:
当spring容器启动的时候,
ApplicationContext context = new ClassPathXmlApplicationContext("cn/itcast/spring0401/di/annotation/applicationContext.xml");
spring容器会创建纳入spring容器管理的bean.分别为person和student;
spring容器会解析配置文件,会解析到<context:annotation-config>
</context:annotation-config>,会在纳入spring的bean范围内查找属性上是否存在
@Resource(name="student")
* 如果存在:
* 继续解析@Resource有没有name属性
* 如果没有name属性就会在所属的属性上,把属性的名称解析出来。会让属性的名称和spring中的bean中的id进行匹配,如果匹配成功,则把spring容器中相应的对象赋值给该属性。如果匹配不成功,则按照类型进行匹配
* @Resource有name属性就会解析name属性的值,把这个值和spring容器中的bean的id进行匹配
* 如果匹配成功,则把spring容器中的相应的对象赋值给该属性
* 如果匹配不成功,则直接报错
* 如果不存在:不做任何事情
xml和注解的写法:
xml:书写比较麻烦,但是效率比较高
注解:书写比较简单,但是效率比较低
注解的写法只适合引用
Spring自己的注解注入类型:
@Autowired:@Autowired 默认按类型装配,@Resource默认按名称装配,当找不到与名称匹配的bean才会按类型装配
@Qualifier:使用按名称装配,可以结合@Qualifier注解一起使用
@Resource: 名称可以通过@Resource的name属性指定,如果没有指定name属性,
• 当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象
• 当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。
@PostConstruct:指定Bean的初始化方法
@PreDestroy:指定Bean的销毁方法
Spring注解自动扫描原理:
* 类扫描的注解解析器包含了依赖注入的注解解析器
* 原理:
当启动spring容器的时候,
ApplicationContext context = new ClassPathXmlApplicationContext("cn/itcast/spring0401/scan/applicationContext.xml");
spring容器会加载配置文件,并且解析配置文件,就会解析到
* 类扫描的注解解析器,会在base-package包及子包中扫描所有的类
* 检查类上是否有@Compontent注解
* 如果有
* @Compontent是否有value属性
* 没有value属性 则会把这个注解所在的类的类名的第一个字母变成小写,其余的不变当做bean的id
* 如果有value属性 则value属性的值就是bean的id
* 如果没有
* 类扫描注解解析完以后,所有的在base-package包及子包下的带有@Compontent注解的类就被纳入spring管理了
* 在纳入spring管理的类中扫描各个属性,看属性是否有@Resource,再根据这个注解的规则进行操作。
* 扫描的次数:
* 根据base-package包及子包进行扫描
* 扫描纳入spring管理的所有的bean的属性
* 属性的name的值和bean中的id进行匹配
<context:component-scan base-package="cn.vijayt"/>----->@Repository
、@Service
和 @Controller
Spring继承:
在Spring中继承关系不能在JAVA类中建立,必须在Spring容器的配置文件中建立继承关系,利用parent="父类"来建立