阿里二面:Spring框架使用了哪些设计模式?

简介: 阿里二面:Spring框架使用了哪些设计模式?

1 简单工厂模式

当A对象需要调用B对象的方法时,我们需要在A中new一个B的实例,我们把这种方式叫作硬编码耦合,缺点是一旦需求发生变化,比如需要使用C类来代替B时,就要改写A类的方法。


假如应用中有上千个类以硬编码的方式耦合了B,改就很头疼。

于是有了简单工厂模式,又叫静态工厂方法,就是由一个工厂类根据传入参数,动态决定应该创建哪个产品类。


Spring中的BeanFactory就是简单工厂模式的体现,BeanFactory是Spring IOC容器中的一个核心接口,它的定义如下:image.png可以通过它的具体实现类(如ClassPathXmlApplicationContext)获取Bean:

BeanFactory bf = new ClassPathXmlApplicationContext("spring.xml");
User userBean = (User) bf.getBean("userBean");

使用者无需自己new,而是通过工厂类的方法getBean获取对象实例,这就是简单工厂模式,只不过Spring是用反射创建Bean。

2 工厂方法模式

简单工厂中,由工厂类进行所有的逻辑判断、实例创建。

如果不想在工厂类中进行判断,可为不同产品提供不同工厂,不同工厂生产不同产品,每个工厂都只对应一个相应对象,这就是工厂方法模式。


Spring FactoryBean,工厂Bean

image.png

定义一个类UserFactoryBean实现FactoryBean接口,主要是在getObject方法里new一个User对象

这样通过getBean(id) 获得的是该工厂所产生的User实例,而非UserFactoryBean本身实例:

BeanFactory bf = new ClassPathXmlApplicationContext("user.xml");
User userBean = (User) bf.getBean("userFactoryBean");

3 单例模式

一个类在整个系统运行过程中,只允许产生一个实例。

Spring Bean默认是单例模式。Spring 通过单例注册表(HashMap)方式:

public class DefaultSingletonBeanRegistry {
    // 使用 ConcurrentHashMap 保存各种单实例对象
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>;
    protected Object getSingleton(String beanName) {
    // 先到 Map 中拿Object
    Object singletonObject = singletonObjects.get(beanName);
    // 若没拿到通过反射创建一个对象实例,并添加到HashMap中
    if (singletonObject == null) {
      singletonObjects.put(beanName,
                           Class.forName(beanName).newInstance());
   }
   // 返回对象实例
   return singletonObjects.get(beanName);
  }
}

4 代理模式

它与被代理对象实现相同接口,客户端必须通过代理才能与被代理的目标类进行交互,而代理一般在交互的过程中(交互前后),进行某些特定处理,比如在调用这个方法前做前置处理,调用这个方法后做后置处理。

好处

可以在目标对象业务功能的基础上添加一些公共的逻辑,比如我们想给目标对象加入日志、权限管理和事务控制等功能,我们就可以使用代理类来完成,而没必要修改目标类,从而使得目标类保持稳定。


符合开闭原则,不要随意修改别人写好的代码或方法。


代理又分为

静态代理

需要定义接口,被代理对象(目标对象)与代理对象(Proxy)一起实现相同接口:

// 抽象接口
public interface IStudentDao {
    void save();
}
// 目标对象
public class StudentDao implements IStudentDao {
    public void save() {
        System.out.println("保存成功");
    }
}
// 代理对象
public class StudentDaoProxy implements IStudentDao{
    //持有目标对象的引用
    private IStudentDao target;
    public StudentDaoProxy(IStudentDao target){
        this.target = target;
    }
    //在目标功能对象方法的前后加入事务控制
    public void save() {
        System.out.println("开始事务");
        target.save();//执行目标对象的方法
        System.out.println("提交事务");
    }
}
public static void main(String[] args) {
    //创建目标对象
    StudentDao target = new StudentDao();
    //创建代理对象,把目标对象传给代理对象,建立代理关系
    StudentDaoProxy proxy = new StudentDaoProxy(target);
    //执行的是代理的方法
    proxy.save();
}

动态代理

Spring AOP采用动态代理,即代理类在程序运行时由JVM动态创建。

静态代理的例子中,代理类(StudentDaoProxy)是自定义的,在程序运行之前就已经编译完成。

而动态代理,代理类并不是在Java代码中定义,而是在运行时根据我们在Java代码中的“指示”动态生成的。


怎么“指示”JDK去动态地生成代理类呢?


在Java的java.lang.reflect包里提供了一个Proxy类和一个InvocationHandler接口,通过这个类和这个接口可以生成动态代理对象:

1.定义一个InvocationHandler类,将需要扩展的逻辑集中放到这个类中。

比如下面的例子模拟了添加事务控制:

public class MyInvocationHandler implements InvocationHandler {
    private Object obj;
    public MyInvocationHandler(Object obj){
        this.obj=obj;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        System.out.println("开始事务");
        Object result = method.invoke(obj, args);
        System.out.println("开始事务");
        return result;
    }
}
  1. 使用 Proxy#newProxyInstance 动态创建代理对象
public static void main(String[] args) {
  //创建目标对象StudentDao
  IStudentDao stuDAO = new StudentDao();
  //创建MyInvocationHandler对象
  InvocationHandler handler = new MyInvocationHandler(stuDAO);
  //使用Proxy.newProxyInstance动态的创建代理对象stuProxy
  IStudentDao stuProxy = (IStudentDao) 
 Proxy.newProxyInstance(stuDAO.getClass().getClassLoader(), stuDAO.getClass().getInterfaces(), handler);
  //动用代理对象的方法
  stuProxy.save();
}

动态代理的优势在于可以很方便地对代理类的函数进行统一的处理,而不用修改每个代理类中的方法。


Spring实现了通过动态代理对类进行方法级别的切面增强,即动态生成目标对象的代理类,并在代理类的方法中设置拦截器,通过执行拦截器中的逻辑增强了代理方法的功能,从而实现AOP。

目录
相关文章
|
3月前
|
安全 Java 应用服务中间件
阿里技术官架构使用总结:Spring+MyBatis源码+Tomcat架构解析等
分享Java技术文以及学习经验也有一段时间了,实际上作为程序员,我们都清楚学习的重要性,毕竟时代在发展,互联网之下,稍有一些落后可能就会被淘汰掉,因此我们需要不断去审视自己,通过学习来让自己得到相应的提升。
|
4月前
|
架构师 安全 前端开发
阿里P9架构师推荐的Spring领域巅峰之作,颠覆了我对Spring的认知
你第一次接触spring框架是在什么时候?相信很多人和我一样,第一次了解spring都不是做项目的时候用到,而是在网上看到或者是听到过一个叫做spring的框架,这个框架号称完爆之前的structs和structs2,吸引了不少人的注意。
|
7天前
|
设计模式 Java 数据库连接
Spring Framework 6 中的设计模式
Spring Framework 6 中的设计模式
18 1
|
27天前
|
设计模式 Java 数据库连接
9种设计模式在Spring中的运用
9种设计模式在Spring中的运用
70 0
|
设计模式 Java 数据库连接
Spring设计模式(一)
Spring设计模式(一)
|
3月前
|
设计模式 Java Spring
Spring5深入浅出篇:Spring工厂设计模式拓展应用
Spring5深入浅出篇:Spring工厂设计模式拓展应用
|
3月前
|
设计模式 Java Spring
Spring5深入浅出篇:Spring与工厂设计模式简介
Spring5深入浅出篇:Spring与工厂设计模式简介
|
3月前
|
安全 Java 数据库连接
啃完这些Spring知识点,我竟吊打了阿里面试官(附面经+笔记)
对于开发同学来说,Spring 框架熟悉又陌生。 熟悉:开发过程中无时无刻不在使用 Spring 的知识点;陌生:对于基本理论知识疏于整理与记忆。导致很多同学面试时对于 Spring 相关的题目知其答案,但表达不够完整准确。
|
3月前
|
机器学习/深度学习 安全 Java
硬核!阿里2023版Spring全家桶进阶笔记流出,堪称Java跳槽神器
最近小伙伴在我后台留言是这样的: 现在就这光景,不比以前,会个CRUD就有人要,即使大部分公司依然只需要做CRUD的事情......现在去面试,只会CRUD还要被吐槽: 面试造火箭,工作拧螺丝,就是现在互联网最真实的写照。很多程序员都是死磕八股文,以应对面试。这种情况无可厚非,但其实最重要的还是技术基础和深度学习。真正能用上的能有多少,不是看现在,还有未来!所以,以技术立命,我们能做的也就只有不断提升自己,去适应市场环境,提高自身技术水平!但这可不是一件简单的事情,虽然也可以自学,但站在巨人的肩膀上学习才是能让程序员事半功倍的最优道路。
硬核!阿里2023版Spring全家桶进阶笔记流出,堪称Java跳槽神器
|
4月前
|
前端开发 Java 开发者
阿里内部热捧“Spring全线笔记”,不止是全家桶,太完整了
对于每一位Java开发人员来说,提起Spring定是不陌生的,实际上自Spring框架诞生以来,就备受开发者的青睐,基本上现在的互联网公司都要使用到Spring框架。Spring框架中又包含了SpringMVC、SpringBoot、SpringCloud等,被开发者称呼为Spring全家桶。