Spring框架概述
Spring是轻量级的开源JavaEE框架,解决企业应用开发的复杂性。其中的核心部分有ICO(控制反转,将创建对象的过程交给Spring进行管理,不再通过传统的new方式)和AOP(面向切面,不修改源代码的基础上进行功能增强)。Spring特点有:方便解耦,简化开发、AOP编程、方便测试、方便与其他框架整合、事务操作等
IOC
IOC
:控制反转,将对象创建过程与对象之间的调用过程,交给Spring进行管理,降低代码耦合度。简单说就是假如类A中依赖类B,不再通过new的方式注入依赖,而是将对象托管给Spring帮我们进行创建管理,我们只需在使用的时候,通过自动注入即可。
IOC过程(xml+反射实现)
1.加载spring配置文件
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="student" class="cn.xfnihao.entity.Student">
<property name="id" value="1"></property>
<property name="name" value="xf"></property>
<property name="phone" value="123456789"></property>
</bean>
</beans>
2.反射获取对象实例
/**
* 工厂类
*/
public class StudentFactory {
public static Student getInstance()throws Exception{
String classValue=classValue; // classValue="cn.xfnihao.entity.Student"
Class cls=Class.forName(classValue); //反射
return (Student) cls.newInstance();
}
}
通过xml配置文件+反射,就可以简单模拟实现IOC的过程
IOC过程(核心接口)
- IOC两个核心接口
1.BeanFactory
IOC容器基本实现,也是IOC顶级接口,主要是Spring出厂内部组件实例化使用,通常我们使用的是它的子接口,不提供开发人员进行使用,加载配置文件时不会创建对象,在获取对象(使用)才去创建对象(类似懒加载)
public class TestSpring {
@Test
public void test(){
//1.加载spring配置文件,未创建对象
BeanFactory ac=new ClassPathXmlApplicationContext("spring.xml");
//2.获取bean对象
Student student = ac.getBean("student", Student.class); //创建对象
System.out.println(student);
}
}
2.ApplicationContext
BeanFactory的子接口,提供更强大的功能,在加载配置文件时就创建对象,预先帮我们进行了Bean的创建和管理,开发人员只管使用即可。
public class TestSpring {
@Test
public void test(){
//1.加载spring配置文件,并创建对象
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
//2.获取bean对象
Student student = ac.getBean("student", Student.class); //创建对象
System.out.println(student);
}
}
Spring两大类型Bean
Spring中有两种类型的Bean:FactoryBean
和普通Bean
- FactoryBean(工厂Bean
在配置文件中定义的Bean类型可以和返回类型不一样,通常要实现FactoryBean接口,在实现方法中获取指定返回的Bean
/**
* 工厂Bean
*/
public class XfBean implements FactoryBean<Student> {
@Override
public boolean isSingleton() {
return true;
}
@Override
public Student getObject() throws Exception {
//返回具体Bean
return new Student();
}
@Override
public Class<?> getObjectType() {
return null;
}
}
//配置文件
<bean id="xfBean" class="cn.xfnihao.entity.XfBean"></bean>
//测试
@Test
public void testBean(){
//1.加载spring配置文件,并创建对象
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
//2.获取bean对象
Student student = ac.getBean("xfBean", Student.class); //创建对象
System.out.println(student);
}
- 普通Bean
在配置文件中定义的Bean类型,就是返回类型
Spring创建Bean过程、生命周期
既然Spring容器替我们做了Bean的管理,那它是怎样创建Bean的呢?首先明白一点,Spring启动,就自动为我们创建好了Bean,需要的时候直接拿来用,我们一起来具体创建过程。
根据上图大致得出:Spring在启动通过读取配置文件夹或者Java配置类来获取Bean的配置信息,并生成一份相应的Bean定义注册表,然后根据注册表来实例化Bean,最后将实例后的Bean放入一个Bean的缓存池中。当程序需要使用Bean,直接从缓存池中获取.
在Spring中,可以设置Bean的多种作用域,一般常用的有单实例(singleton)
和多实例(prototype)
,默认为singleton,不过在多线程环境下,单实例可能会引起线程安全问题,我们需要针对具体场景来手动设置Bean的作用域。
- 单实例
@Test
public void test(){
//1.加载spring配置文件,并创建对象
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
//2.获取bean对象
Student student1 = ac.getBean("student", Student.class);
Student student2=ac.getBean("student", Student.class);
System.out.println(student1); //cn.xfnihao.entity.Student@a74868d
System.out.println(student2); //cn.xfnihao.entity.Student@a74868d
System.out.println(student1==student2); //true
}
- 多实例
修改配置文件,设置Bean的scope属性,当然也可以设置为singleton,不设置就默认为singleton
<bean id="student" class="cn.xfnihao.entity.Student" scope="prototype"></bean>
@Test
public void test(){
//1.加载spring配置文件,并创建对象
ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
//2.获取bean对象
Student student1 = ac.getBean("student", Student.class);
Student student2=ac.getBean("student", Student.class);
System.out.println(student1); //cn.xfnihao.entity.Student@a74868d
System.out.println(student2); //cn.xfnihao.entity.Student@12c8a2c0
System.out.println(student1==student2); //false
}
生命周期
:一个对象从创建到销毁的整个过程称为Bean的生命周期,在Spring中,Bean的生命周期包括以下几步:
1.Bean的创建,主要通过调用无参构造
2.调用set方法注入Bean属性
3.执行初始化前的方法(BeanPostProcessor的postProcessBeforeInitialization)
4.执行初始化方法
5.执行初始化后的方法(BeanPostProcessor的postProcessAfterInitialization)
6.获取Bean实例,并使用
7.容器关闭,销毁Bean
//Bean
public class Student {
private Integer id;
private String name;
private String phone;
public Student(){
System.out.println("1.执行无参构造创建对象");
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
System.out.println("2.通过set方法注入属性值");
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public void init(){
System.out.println("4.init()初始化方法");
}
public void destroy(){
System.out.println("7.destroy()销毁方法");
}
}
//BeanProcessor
public class XfBeanProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("3.BeanPostProcessor的postProcessBeforeInitialization");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("5.BeanPostProcessor的postProcessAfterInitialization");
return bean;
}
}
//配置文件
<bean id="student" class="cn.xfnihao.entity.Student" init-method="init" destroy-method="destroy">
<property name="id" value="1"></property>
<property name="name" value="xf"></property>
<property name="phone" value="18286236432"></property>
</bean>
<bean id="xfBeanProcessor" class="cn.xfnihao.XfBeanProcessor"></bean>
//test
@Test
public void test(){
//1.加载spring配置文件,并创建对象
ClassPathXmlApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");
//2.获取bean对象
Student student = ac.getBean("student", Student.class);
System.out.println("6.获取Bean实例:"+student);
ac.close(); //关闭容器
}
运行截图:
AOP
AOP
:(面向切面编程),作为Spring另一个核心模块,利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。常用于权限检查,事务控制,日志,程序耗时计算等非核心业务逻辑。
AOP 领域中的特性术语:
- 通知(Advice): AOP 框架中的增强处理。通知描述了切面何时执行以及如何执行增强处理。
- 连接点(join point): 连接点表示应用执行过程中能够插入切面的一个点,这个点可以是方法的调用、异常的抛出。在 Spring AOP 中,连接点总是方法的调用。
- 切点(PointCut): 可以插入增强处理的连接点。
- 切面(Aspect): 切面是通知和切点的结合。
- Spring 中的 AOP 是通过动态代理实现的。
Spring AOP简单实现
/**
* 接口
*/
public interface IBuy {
String buy();
}
/**
* BoyBuy实现类
*/
@Component
public class BoyBuy implements IBuy {
@Override
public String buy() {
System.out.println("男孩买了一个游戏机");
return "游戏机";
}
}
定义切面类:
/**
* 切面类
*/
@Aspect
@Component
public class BuyAspectJ {
//前置通知:目标方法执行前调用
@Before("pointCut()")
public void before(){
System.out.println("before is called");
}
//后置通知:目标方法执行后调用
@After("pointCut()")
public void after(){
System.out.println("after is called");
}
//环绕通知:将目标方法封装起来,必须传入ProceedingJoinPoint对象
//并且需要调用 ProceedingJoinPoint 的 proceed() 方法。
@Around("pointCut()")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("around before");
joinPoint.proceed();
System.out.println("around after");
}
//后置返回通知:目标方法返回后调用
@AfterReturning("pointCut()")
public void afterReturning(){
System.out.println("afterReturning is called");
}
//优化切点表达式;
//当多个通知增强同一方法时,为减少代码重复性,可以用@Pointcut出抽取相同的切点表达式
//并用任意方法接管
@Pointcut("execution(* cn.xfnihao.dao.IBuy.buy(..))")
public void pointCut(){
}
}
测试:
//测试
@Test
public void testAop(){
ApplicationContext ac=new AnnotationConfigApplicationContext(App.class);
BoyBuy boyBuy=ac.getBean("boyBuy",BoyBuy.class);
boyBuy.buy();
}
结果打印:
在实际开发中,AOP的运用比这个更复杂,不过思想是一致的。简单总结就是在原来的功能基础上,实现增强,额外定制(说白了就是你觉得这个程序还不足够完美,但你又不想去破坏程序原有的逻辑,所以你可以用AOP实现你想达到的效果)
总结
本篇主要讲到Spring的两个核心技术IOC和AOP,对比传统开发,Spring容器帮我们进行了Bean的管理,很大程度上降低了代码之间的耦合度,并用注解开发演示了IOC的Bean管理;借助AOP的编程思想,不需要去改动原先的程序代码就能够实现代码的可重用性,提升了开发效率,并且也降低了业务开发的耦合度。