Spring核心概念

Spring 的两大特性就是 IoC 和 AOP。

1. 什么是 IoC

IoC叫控制反转。在谈IoC之前,要了解什么是容器,因为Spring又叫IoC容器。容器是一个软件环境,它为某种特定组件的运行提供环境支持。例如,Tomcat就是一个Servlet容器,它可以为Servlet的运行提供运行环境。Docker也是一个容器,它提供了必要的Linux环境以便运行一个特定的Linux进程。

通常的Java程序,在需要一个类的时候,都是自己主动去创建,也就是说,控制权在程序本身,一个组件在哪里需要就在哪里创建。这种创建组件方式的问题是,在一个大型系统中,各种组件随意创建,相互依赖,会让对象管理的复杂度变高,也极大提升了组件之间的耦合度,不利于程序的维护和测试。

在IoC模式下,控制权发生反转,组件不由程序自己创建,而是在IoC容器中创建。程序依赖某个组件,从IoC容器中拿来即用。而这个“拿来”的过程,又是一个组件注入的过程,因此IoC又叫做依赖注入(DI)。

IoC的好处:将组件的创建、配置与组件的使用解耦,且由IoC容器来管理组件的生命周期。

2. 什么是 AOP

AOP是即面向切面编程。AOP本质上就是一个代理模式,使得调用方能无感知地调用指定方法,但运行期却动态“织入”了其他逻辑。

Spring AOP的实现有两种方式:JDK动态代理和CGLIB代理:

  1. 对实现接口的类使用JDK动态代理,
  2. 对普通类使用CGLIB创建子类来实现代理。

Spring AOP选择代理方式的代码位置:DefaultAopProxyFactory

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
	...
	
	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (!NativeDetector.inNativeImage() &&
				(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " +
						"Either an interface or a target is required for proxy creation.");
			}
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass) || ClassUtils.isLambdaClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}
	
	...
}

2.1 AOP 问题

CGLIB代理因为是通过创建被代理类的子类来实现扩展,所以它又称子类代理。因此使用CGLIB代理要注意的问题是:

  1. 被代理类不能申明为final
  2. 被代理类中的方法如果为static或final,不会被代理

另外,Spring通过CGLIB创建的代理类,不会初始化代理类自身继承的任何成员变量,包括final类型的成员变量!因此,正确使用AOP,我们需要一个避坑指南:

  1. 访问被注入的Bean时,总是调用方法而非直接访问字段;
  2. 编写Bean时,如果可能会被代理,就不要编写public final方法。
  3. 如果不想Bean被代理,就申明为final类,也不实现接口。
posted @ 2023-06-13 09:06  xfcoding  阅读(6)  评论(0编辑  收藏  举报