发送 三、Spring 的Ioc
一、预备知识:反射
1.反射的基本概念
在运行期间,动态获取类的基本信息(类的属性、类的构造方法、类的普通方法)
2.反射的使用Class
(1)获取Class对象的三种方式
package org.test;
import org.lanqiao.Student;
import java.lang.reflect.*;
public class Test {
public static void getClassInfo(String className) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException, NoSuchMethodException {
//第一种通过类.class获取Class对象
//Class c = Student.class;
//第二种方式:通过forName()
//Class c = Class.forName(className);
//第三种方式:通过类的对象获取类的信息
Student student = new Student();
Class c = student.getClass();
//获取该类的属性
/* Field[] fields = c.getFields(); //获取该类及从父类继承下来的所有公有public属性(不包括私有)
for (Field field : fields) {
System.out.println(field.getName());
System.out.println(field.getType());
System.out.println(Modifier.toString(field.getModifiers()));
}*/
//获取本类自己定义的所有的属性
Field[] declaredFields = c.getDeclaredFields();
for (Field declaredField : declaredFields) {
System.out.println(declaredField.getName());
System.out.println(declaredField.getType());
System.out.println(Modifier.toString(declaredField.getModifiers()));
}
declaredFields[0].setAccessible(true);//暴力访问私有变量
declaredFields[0].set(student,"赵六");
System.out.println(student.getName());
//Constructor[] constructors = c.getConstructors();
/*for (Constructor constructor : constructors) {
System.out.println(constructor.getName());
System.out.println(constructor.getParameterCount());
Parameter[] parameters = constructor.getParameters();
for (Parameter parameter : parameters) {
System.out.println(parameter.getName()+","+parameter.getType());
}
}*/
/* Constructor constructor = c.getConstructor(int.class, String.class, int.class);
Student student2 = (Student) constructor.newInstance(180,"张三",21);
System.out.println(student2);
*//*System.out.println(student.getName());*//*
Method method = c.getMethod("study", String.class);
method.invoke(student2,"王五");*/
/* Method[] methods = c.getMethods();
for (Method method : methods) {
System.out.println(method.getReturnType());
System.out.println(method.getName());
}*/
/* Method[] declaredMethods = c.getDeclaredMethods();
for (Method method : declaredMethods) {
System.out.println(method.getReturnType());
System.out.println(method.getName());
}
declaredMethods[4].invoke(student,"李四");*/
//System.out.println(o);
}
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InvocationTargetException, InstantiationException , NoSuchMethodException {
getClassInfo("org.lanqiao.Student");
}
}
二、Spring框架的基本概念
1.Spring的基本概念
Spring是一个开源框架,它由[Rod Johnson](https://baike.baidu.com/item/Rod Johnson)创建。它是为了解决企业应用开发的复杂性而创建的。Spring使用基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅限于服务器端的开发。从简单性、可测试性和松耦合的角度而言,任何Java应用都可以从Spring中受益。
Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
### 2.Spring的作用
IoC提供松耦合 ,解耦使用的
package org.test;
import org.lanqiao.IHello;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test2 {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("beans.xml");
IHello hello = (IHello) applicationContext.getBean("hello");
hello.sayHello();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--委托Spring IoC容器创建并管理该bean的对象 -->
<bean id="hello2" class="org.lanqiao.Hello"></bean>
<bean id="hello" class="org.lanqiao.Hello2"></bean>
<bean id="student" class="org.lanqiao.Student"></bean>
</beans>
三、Spring 的Ioc
1.Ioc控制反转的概念
IoC Inverse of Control 控制反转
把创建对象的方式在代码交给了Spring Container容器来创建
bean的创建、使用、销毁都交给IoC容器处理
2.Bean的生命周期
<bean id="hello2" class="org.lanqiao.Hello" init-method="init" destroy-method="d"></bean>
(1)创建
一种只要ioc容器启动,bean就被实例化,单例模式
一种是ioc容器启动时候并没有创建,而是在该对象被调用的时候才创建出来
(2)初始化
init-method="init"
(3)使用
调用bean的普通方法
(4)销毁
destroy-method,并不是直接从内存中移除,而是做标记告知由GC来进行回收
### 3.Bean的范围
scope:
singleton:单例(默认)
prototype:原型(多例)
在web的应用程序中:
scope=“request”
scope=“session”
scope=“application”
单例和多例的区别:
(1)单例是在IOC容器只存在一个对象,多例模式就会有多个对象
(2)单例模式只要ioc容器启动就会被创建,多例模式只有在使用的时候才被创建
四、Spring 的DI
DI dependency injection 依赖注入,给创建的bean的对象赋值
(一)根据依赖注入的方式
1.属性注入方式
<bean id="student" class="org.lanqiao.Student">
<!--依赖注入-->
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="age" value="21"/>
</bean>
2.构造方法注入方式
可以通过构造方法的参数名,参数索引和参数类型等进行注入,推荐使用参数名(直观)
<!--Student student01 = new Student(2,"李四",21);-->
<bean id="student01" class="org.lanqiao.Student">
<constructor-arg name="id" value="2"/>
<constructor-arg name="name" value="李四"/>
<constructor-arg name="age" value="21"/>
<!--<constructor-arg index="0" value="2"/>
<constructor-arg index="1" value="李四2"/>
<constructor-arg index="2" value="23"/>-->
</bean>
3.通过工厂方式注入
工厂的作用生产对象,可以在创建对象的同时做一些其他事情
<!--使用非静态工厂-->
<bean id="studentFactory" class="org.lanqiao.factory.StudentFactory"/>
<bean id="student02" factory-bean="studentFactory" factory-method="create"/>
<!--使用静态工厂-->
<bean id="student03" class="org.lanqiao.factory.StudentFactory2" factory-method="create"/>
4.使用SpEL(spring expression language) #{},支持表达式
<bean id="student04" class="org.lanqiao.Student">
<!--属性SpEL依赖注入,调用setXXX()-->
<property name="id" value="#{1}"/>
<property name="name" value="#{'张三'}"/>
<property name="age" value="#{10+10}"/>
</bean>
5.使用P命名空间的方式
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--使用p命名空间 -->
<bean id="student05" class="org.lanqiao.Student" p:id="5" p:name="孙七" p:age="22"/>
</beans>
根据属性值的类型
1.基本数据类型的注入
<bean id="student" class="org.lanqiao.Student">
<!--依赖注入-->
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="age" value="21"/>
</bean>
2.引用数据类型
<bean id="grade" class="org.lanqiao.Grade">
<property name="id" value="1"/>
<property name="gname" value="大一"/>
</bean>
<bean id="student06" class="org.lanqiao.Student">
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="age" value="21"/>
<property name="grade" ref="grade"/>
</bean>
3.空值注入null
<bean id="student07" class="org.lanqiao.Student">
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="age" value="21"/>
<property name="grade">
<!--注入空值-->
<null></null>
</property>
</bean>
(三)Spring的自动装配
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"
default-autowire="byType">
<bean id="grade" class="org.lanqiao.Grade">
<property name="id" value="1"/>
<property name="gname" value="大一"/>
</bean>
<bean id="student" class="org.lanqiao.Student">
<property name="id" value="1"/>
<property name="name" value="张三"/>
<property name="age" value="21"/>
</bean>
这里的 default-autowire="byType" 的设置表示:在student这个bean中有一个Grade属性没有被声明注入,自动在Spring IoC容器中查找与这个属性相匹配的类型,假如类型一致,会把容器中的这个值注入给该属性
byType不能在IoC中出现重复类型的bean,会造成混乱,不知道要注入哪个bean
byName就是通过属性名相同的bean会自动注入进来
这种设置是全局性,在整个IoC容器都会自动的根据类型或者名称装配,这种方式是有风险的,不建议这样使用