聊聊Spring中的核心IOC和AOP

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的编程思想,不需要去改动原先的程序代码就能够实现代码的可重用性,提升了开发效率,并且也降低了业务开发的耦合度。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值