Day1:Spring-IoC、DI
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安装目录的lib\j2ee\common-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="父类"来建立