信任这个点也是面试常考的,面试无非两种,

一种是手撕( 一次面试设计形式手撕阅历 )

一种便是结合结构问

前置常识

设计形式:

菜鸟教程教的仍是十分详细的 墙裂推荐!!

www.runoob.com/design-patt…

收拾的代码:

github.com/scwlkq/java…

Spring中的设计形式

署理形式

比如 鸡哥是个明星,他有个经纪人,协作的工作都是由经纪人署理履行

静态署理

静态署理中,咱们对方针方针的每个办法的增强都是手动完成的(后面会详细演示代码),十分不灵敏(比如接口一旦新增加办法,方针方针和署理方针都要进行修正)且费事(需求对每个方针类都独自写一个署理类)。 实践运用场景十分十分少,日常开发几乎看不到运用静态署理的场景。

代码:

咱们界说一个用户服务类

public interface UserService {
    String login(String username, String password);  
}

给出它的完成:

public class UserServiceImpl implements UserService {
    @Override  
    public String login(String username, String password) {  
        if("admin".equals(username) && "123456".equals(password)){  
            return "ok";  
        }  
    return "no";  
    }  
}

这时候的署理类:

public class UserProxy implements UserService {
    private final UserService userService;  
    public UserProxy(UserService userService) {  
        this.userService = userService;  
    }  
    @Override  
    public String login(String username, String password) {  
        //调用办法之前,咱们能够增加自己的操作  
        System.out.println("before method login()");  
        String result = userService.login(username, password);  
        //调用办法之后,咱们相同能够增加自己的操作  
        System.out.println("after method login()");  
        return result;  
    }  
}

运用:

public class Main {
    public static void main(String[] args) {  
        UserService userService = new UserServiceImpl();  
        UserProxy userProxy = new UserProxy(userService);  
        System.out.println(userProxy.login("admin", "123456"));  
    }  
}

针对每个服务 咱们需求完成对应的办法的署理,很不便利

动态署理

比较于静态署理来说,动态署理愈加灵敏。咱们不需求针对每个方针类都独自创立一个署理类,并且也不需求咱们有必要完成接口,咱们能够直接署理完成类(CGLIB 动态署理机制)。

jdk署理

也便是说:你通过Proxy 类的 newProxyInstance() 创立的署理方针在调用办法的时候,实践会调用到完成InvocationHandler 接口的类的 invoke()办法。 你能够在 invoke() 办法中自界说处理逻辑,比如在办法履行前后做什么工作。

JDK 动态署理有一个最致命的问题是其只能署理完成了接口的类。

代码示例:

首要界说一个接口和完成类:

public interface UserService {
    String login(String username, String password);  
}
public class UserServiceImpl implements UserService {
    @Override  
    public String login(String username, String password) {  
        if("admin".equals(username) && "123456".equals(password)){  
            return "ok";  
        }  
        return "no";  
    }  
}

然后 咱们完成InvocationHandler这个处理接口:

这个能够理解为 你要署理类在这个办法前后干些啥

public class DebugInvocationHandler implements InvocationHandler {
    private final Object target;  
    public DebugInvocationHandler(Object object){  
        this.target = object;  
    }  
    @Override  
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
        System.out.println("before:"+method.getName());  
        Object result = method.invoke(target, args);  
        System.out.println("after:"+method.getName());  
        return result;  
    }  
}

再界说一个Jdk署理类的工厂:

import java.lang.reflect.Proxy;
public class JdkProxyFactory {  
    public static Object getProxy(Object target){  
        System.out.println(target.getClass().getClassLoader());  
        return Proxy.newProxyInstance(  
            target.getClass().getClassLoader(),  
            target.getClass().getInterfaces(),  
            new DebugInvocationHandler(target)  
            );  
    }  
}

运用:

public class Main {
    public static void main(String[] args) {  
        UserService userService = (UserService) JdkProxyFactory.getProxy(new UserServiceImpl());  
        System.out.println(userService.login("admin", "123456"));  
    }  
}

整理Spring中常用的设计模式

CGLib署理

CGLIBopen in new window(Code Generation Library)是一个基于ASMopen in new window的字节码生成库,它允许咱们在运行时对字节码进行修正和动态生成。CGLIB 通过承继办法完成署理。(你能够看到下面的Enhancer类便是承继的被署理方针)

简而言之,你需求引入CGLIB的maven依靠

<dependency>
    <groupId>cglib</groupId> 
    <artifactId>cglib</artifactId>
    <version>3.3.0</version> 
</dependency>

界说一个办法:

public class UserService {
    public String login(String username, String password) {  
        if("admin".equals(username) && "123456".equals(password)){  
            return "ok";  
        }  
        return "no";  
    }  
}

关键是要完成这个MethodInterceptor:

public class DebugMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //调用办法之前,咱们能够增加自己的操作
        System.out.println("before method " + method.getName());
        Object object = methodProxy.invokeSuper(o, objects);
        //调用办法之后,咱们相同能够增加自己的操作
        System.out.println("after method " + method.getName());
        return object;
    }
}

然后相同构建factory:

public class CglibProxyFactory {
    public static Object getProxy(Class<?> clazz){
        // 创立动态署理增强类
        Enhancer enhancer = new Enhancer();
        // 设置类加载器
        enhancer.setClassLoader(clazz.getClassLoader());
        // 设置被署理类
        enhancer.setSuperclass(clazz);
        // 设置办法拦截器
        enhancer.setCallback(new DebugMethodInterceptor());
        // 创立署理类
        return enhancer.create();
    }
}

运用:

public class Main {
    public static void main(String[] args) {
        UserService userService = (UserService) CglibProxyFactory.getProxy(UserService.class);
        System.out.println(userService.login("admin", "123456"));
    }
}
JDK 动态署理和 CGLIB 动态署理比照
  1. JDK 动态署理只能署理完成了接口的类或许直接署理接口,而 CGLIB 能够署理未完成任何接口的类。
  2. JDK 动态署理功率更优异。
静态署理和动态署理的比照
  1. 灵敏性:动态署理愈加灵敏,不需求有必要完成接口,能够直接署理完成类。别的,静态署理中,接口一旦新增加办法,方针方针和署理方针都要进行修正,这是十分费事的!
  2. JVM 层面:静态署理在编译时就将接口、完成类、署理类这些都变成了一个个实践的 class 文件。而动态署理是在运行时动态生成类字节码,并加载到 JVM 中的。留意 动态署理都是在运行时动态生成字节码文件

单例形式

  1. 在Spring的配置文件中界说该类的Bean:
<bean id="mySingleton" class="com.example.MySingleton" scope="singleton"/>
  1. Java代码中获取该Bean:
ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
MySingleton mySingleton = (MySingleton) context.getBean("mySingleton");
mySingleton.doSomething();

在上面的代码中,咱们在Spring的配置文件中界说了一个名为mySingleton的Bean,它的类是com.example.MySingleton,效果域为singleton(即单例)。然后在Java代码中,咱们通过ApplicationContext获取该Bean,并调用它的doSomething()办法。

运用Spring结构能够便利地办理单例方针,一起也能够很容易地完成依靠注入和操控回转等功用。

AbstractBeanFactory的getBean里。getBean的doGetBean办法调用getSingleton进行bean的创立。 是一个双检锁的单例

@Override
	@Nullable
	public Object getSingleton(String beanName) {
		return getSingleton(beanName, true);
	}
	/**
	 * Return the (raw) singleton object registered under the given name.
	 * <p>Checks already instantiated singletons and also allows for an early
	 * reference to a currently created singleton (resolving a circular reference).
	 * @param beanName the name of the bean to look for
	 * @param allowEarlyReference whether early references should be created or not
	 * @return the registered singleton object, or {@code null} if none found
	 */
	@Nullable
	protected Object getSingleton(String beanName, boolean allowEarlyReference) {
		Object singletonObject = this.singletonObjects.get(beanName);
		if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
			synchronized (this.singletonObjects) {
				singletonObject = this.earlySingletonObjects.get(beanName);
				if (singletonObject == null && allowEarlyReference) {
					ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
					if (singletonFactory != null) {
						singletonObject = singletonFactory.getObject();
						this.earlySingletonObjects.put(beanName, singletonObject);
						this.singletonFactories.remove(beanName);
					}
				}
			}
		}
		return singletonObject;
	}

工厂形式

整理Spring中常用的设计模式

整理Spring中常用的设计模式
在Spring结构中,AbstractBeanFactory是BeanFactory的一个抽象完成,它供给了一些通用的功用和完成细节,以便其他详细的BeanFactory完成能够承继或扩展它。AbstractBeanFactory完成了BeanFactory接口中的大部分办法,并供给了一些额外的办法和功用,例如BeanDefinition的注册和解析、BeanPostProcessor的处理、Bean生命周期办理等。

BeanFactory是Spring结构中的一个核心接口,它界说了一些办法,用于获取和办理Bean方针。BeanFactory接口的详细完成包含:XmlBeanFactory、DefaultListableBeanFactory、ApplicationContext等。这些完成类都承继了AbstractBeanFactory,并在此基础上进行了扩展和优化,以满足不同的运用场景和需求。因而,AbstractBeanFactory和BeanFactory之间是一种承继联系。

在Spring结构中,ApplicationContext和BeanFactory是一种承继联系。ApplicationContext接口扩展了BeanFactory接口,并供给了更多的功用和特性,例如:

  1. 支撑消息国际化和资源访问
  2. 支撑事情发布和监听
  3. 支撑AOP(面向切面编程)和事务办理
  4. 支撑Web运用程序开发

ApplicationContext是Spring结构中最常用的接口之一,它是一个集成了多种功用的容器,能够办理Bean方针的生命周期,并供给了丰富的功用和服务,例如主动安装、依靠注入、Bean后置处理器等。与此比较,BeanFactory接口只供给了最基本的Bean办理功用,没有供给其他高级功用。

因而,ApplicationContext能够看作是BeanFactory的一个超集,它在BeanFactory的基础上进行了扩展和优化,供给了更多的功用和服务,使得开发者能够愈加便利地运用Spring结构。

适配器形式

完成办法:

SpringMVC中的适配器HandlerAdatper。

完成原理:

HandlerAdatper依据Handler规矩履行不同的Handler。

完成进程:

DispatcherServlet依据HandlerMapping回来的handler,向HandlerAdatper建议恳求,处理Handler。

HandlerAdapter依据规矩找到对应的Handler并让其履行,履行完毕后Handler会向HandlerAdapter回来一个ModelAndView,最后由HandlerAdapter向DispatchServelet回来一个ModelAndView。

完成意义:

HandlerAdatper使得Handler的扩展变得容易,只需求增加一个新的Handler和一个对应的HandlerAdapter即可。

因而Spring界说了一个适配接口,使得每一种Controller有一种对应的适配器完成类,让适配器替代controller履行相应的办法。这样在扩展Controller时,只需求增加一个适配器类就完成了SpringMVC的扩展了。

战略形式

十分优雅~

  1. ResourceLoader和Resource接口

ResourceLoader接口界说了获取资源的办法,而Resource接口则表示一个资源方针。在Spring中,ResourceLoader和Resource接口运用战略形式来完成不同类型的资源的加载和处理。

ResourceLoader接口界说了getResource办法,该办法回来一个Resource方针,表示一个资源。Spring中供给了多种Resource完成类,例如ClassPathResource、FileSystemResource、UrlResource等,它们别离用于加载类途径下的资源、文件系统中的资源和URL中的资源。

ResourceLoader和Resource接口之间的联系能够看作是一种战略形式。ResourceLoader接口相当于Context类,而不同类型的Resource完成类相当于详细的战略类。运用ResourceLoader接口能够便利地加载和处理不同类型的资源,而无需关怀详细的完成细节。

  1. HandlerInterceptor接口

HandlerInterceptor是Spring MVC结构中的一个拦截器接口,用于在恳求处理进程中进行拦截和处理。在Spring MVC中,HandlerInterceptor运用战略形式来完成不同类型的拦截器的注册和处理。

HandlerInterceptor接口界说了三个办法:preHandle、postHandle和afterCompletion,别离对应恳求处理前、恳求处理后和恳求处理完成后的处理逻辑。在Spring MVC中,能够通过完成HandlerInterceptor接口来编写自界说的拦截器,并通过配置文件将其注册到Spring MVC结构中。

HandlerInterceptor和拦截器完成之间的联系能够看作是一种战略形式。HandlerInterceptor接口相当于Context类,而不同类型的拦截器完成类相当于详细的战略类。运用HandlerInterceptor接口能够便利地注册和处理不同类型的拦截器,而无需关怀详细的完成细节。

观察者形式

Spring的事情驱动模型用了「观察者形式」,详细完成便是ApplicationContextEvent、ApplicationListener

详细的可拓展机制能够检查另一篇文章:/post/722260…