对IoC的理解
IoC,Inversion of Control,控制反转。将原本由代码操纵的对象操控权,交由第三方容器,即反转给了第三方容器。这种对象的依赖关系管理方式,称为IoC。
IoC是一种思想,是一个概念。其实现方式很多,较著名的有两种:
DL:Dependency Lookup,依赖查找。其典型应用是JNDI。Java Naming and Directory Interface,Java名称与服务接口。其实JNDI,就是一个第三的容器。
DI:Dependency Injection,依赖注入。是目前最优秀的解耦方式。其典型应用是Spring。
1.Bean的装配(Bean必须有无参构造器)
- bean的装配一般用class属性直接指定该Bean的类名,spring通过反射创建该实例,我们还可以使用Bean工厂进行装配
- 动态工厂Bean的装配:
- 首先我们定义一个工厂类,里边定义一个方法,用来返回一个对象的实例
- 在容器中注册工厂Bean并使用动态工厂方式装配该Bean
- 静态工厂对Bean的装配:
- 该方式不用注册工厂Bean,但在注册car时需要将class属性指定为静态工厂的类全名
2.Bean的作用范围
- 单例模式
- 原型模式(多例)
3.Bean后处理器
- 如果在Bean初始化的前后需要完成一些工作可以使用Bean后处理器
- 该处理器会在容器中每一个Bean初始化前后调用
- 其方法参数为当前Bean
- 应用场景:
- 可以使用动态代理对Bean中的方法进行增强
- 示例代码
public class MyBeanPostProcessor implements BeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName)
throws BeansException {
System.out.println("postProcessBeforeInitialization执行");
return bean;//把执行before后的bean返回
}
@Override
public Object postProcessAfterInitialization(final Object bean, String beanName)
throws BeansException {
//增强bean
Object proxy = Proxy.newProxyInstance(
bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = method.invoke(bean, args);
if(result!=null){
result = ((String) result).toUpperCase();
}
return result;
}
}
);
System.out.println("postProcessAfterInitialization执行");
return proxy;//把增强的代理类返回
}
}
3.DI(依赖注入,即为属性赋值)
1.基于XML的DI
注入的分类:
- 设值注入:使用该方式注入,bean需要有对应的set方法,其原理就是调用bean的set方法为bean的属性赋值 (常用方式)
<bean id="student" class="com.lscw.beans.Student">
<property name="name" value="张三" />
<property name="age" value="23" />
</bean>
- 构造注入:使用bean的构造器对bean的属性进行注入,完成初始化操作
<bean id="student" class="com.lscw.beans.Student" >
<constructor-arg name="name" value="张三" />
<constructor-arg name="age" value="23" />
</bean>
- p命名空间注入:该方式的注入需要引入约束xmlns:p="http://www.springframework.org/schema/p" 使用方式:p:属性名=“属性值”,p:属性名-ref=“bean名称” (不常用)
<bean id="student" class="com.lscw.beans.Student" p:name="张三" p:age="18" />
- c命名空间注入:该方式注入bean需要有对应参数的构造器,需要引入约束xmlns:c="http://www.springframework.org/schema/c"(不常用)
<bean id="student1" class="com.lscw.beans.Student" c:name="李四" c:age="24"/>
- 数组与集合属性的注入
- 域属性的自动注入:域属性也就是对对象的引用
public class Student {
private String name;
private int age;
private School school;//域属性
}
- 域属性自动注入的三种方式
- 通过set方法注入
<bean id="school" class="com.lscw.beans.School">
<property name="address" value="浙江省杭州市" />
</bean>
<bean id="student" class="com.lscw.beans.Student">
<property name="name" value="张三" />
<property name="age" value="23" />
<property name="school" ref="school" />
</bean>
- 域属性的自动注入,ByName方式,容器查找与域属性名称一致的Bean(该bean的id应与属性名一致)
<bean id="student" class="com.lscw.beans.Student" autowire="byName" >
<property name="name" value="张三" />
<property name="age" value="23" />
</bean>
- 域属性的自动注入,ByType方式,容器自动查找与域属性同类型的Bean进行注入,但是容器中不能出现多个同类型的Bean
<bean id="student" class="com.lscw.beans.Student" autowire="byType" >
<property name="name" value="张三" />
<property name="age" value="23" />
</bean>
- SPEL注入:SPEL是spring的表达式,使用方式#{Bean名称.Bean属性名} 注:Bean中必须有get方法
- 内部Bean的注入
<bean id="student" class="com.lscw.beans.Student">
<property name="name" value="张三" />
<property name="age" value="23" />
<property name="school">
<bean class="com.lscw.beans.School">
<property name="address" value="浙江省杭州市" />
</bean>
</property>
</bean>
- 抽象Bean的注入的应用场景:如果多个Bean都需要注入相同的属性,会使Spring的配置文件显得很庞大,并且出现数据冗余的情况,可以使用抽象Bean的注入,定义一个Bean 添加abstract=“true” 属性,则容器初始化时不会创建该Bean。(举个例子,有10个Student对象,这10个student都住在同一个宿舍区,都在同一个班级,对这些学生进行注入时,显然宿舍区和班级都是重复出现的,这时可以注册一个student并添加abstract属性,让其他的学生bean来继承该bean)
- 同类抽象Bean:该抽象Bean与被注入属性的Bean为同一类型
- 异类抽象Bean:该Bean不添加class属性,但是有公用的属性用来被继承
<bean id="base" abstract="true">
<property name="address" value="蓝田4栋"/>
<property name="className" value="高分子1班"/>
</bean>
2.基于注解的DI
- 首先我们要导入Spring-aop的jar包
- 在配置文件中添加context的xsd约束
- 注册组件扫描器
- 基本注解:@C omponent(“BeanId”)可选属性,可以指定Bean的id
-
@Service 一般用于Service类上
@Repository 一般用于Dao类上
@Controller 一般用于SpringMVC中的处理器上
以上三个和@Component功能相同但意义不同
-
@Value(属性值)该注解作用在属性上,相当于<property name="xxx" value="xxx"/>
-
域属性的自动注入@AutoWired 该注解使用ByType注入
-
@AutoWired与@Qualifer结合使用便是ByName方式的注入
-
@Resource默认使用ByType
-
@Resource(name=“xxx”)使用ByName方式注入
-
其他注解:
-
@Scope表示Bean的作用范围 @Scope(“singleton”) 单例 @Scope(“prototype”) 原型模式 该注解作用在类上
-
@AfterInit 作用于方法上 该方法会在Bean初始化以后执行
-
@PreDestroy 该注解作用于方法上该方法会在Bean销毁前执行(spring容器关闭前)执行
-
使用XML装配的优先级比使用注解的优先级高
-
注解使用案例
@Component("student")
@Scope("prototype")
public class Student {
@Value("zs")
private String name;
@Value("23")
private int age;
@Autowired
private School school;
public School getSchool() {
return school;
}
public void setSchool(School school) {
this.school = school;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Student() {
super();
}
public Student(String name, int age) {
super();
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Student [name=" + name + ", age=" + age + ", school=" + school + "]";
}
}