关于Spring我就不再多介绍了,本文主要介绍Spring源码阅读的准备工作。说到spring框架,我们都知道是其基于反射和动态代理实现的。那我们就来看看反射和动态代理……

1.源码获取及编译

  直接从GitHub获取,我就不再做其他描述了。

2.Spring流程图

  Spring的本质是一个bean对象的容器,里面存放了bean对象。那容器最核心的是:存储、获取(查询)、生命周期等,例如我们java中Map,put()存储元素,get()获取元素。那么spring是如何存储bean对象和获取bean对象的呢?还记得我们刚开始学习spring的时候写的配置文件吗?

<!--指定自动注入方式-->
    <bean init-method="initCrazy" id="crazyService" class="cn.crazy.life.CrazyService" autowire="byName">
    </bean>
	
	<!--构造器设置-->
	<bean id="user" class="cn.crazy.domain.User">
		<constructor-arg name="name" value="ZL"/>
		<constructor-arg name="age" value="18"/>
	</bean>
	<bean id="product" class="cn.crazy.domain.Product">
		<property name="name" value="computer"/>
	</bean>

  上面就是利用xml将bean注册到spring。spring根据id和class将对应的bean对象注册进容器中,也可以使用注解的方式进行注入@Component+@Bean

@Component
public class SpringRegister {
	
	@Bean
	public User user(){
		
		return new User("ZL",18);
	}
}

  那如何获取bean呢?使用xml标签"ref"或注解@Autowired。那是根据id还是class来获取bean的?这就是byName和byType问题。今天先不做解释。
  Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。

  • IOC(Inversion of Control,控制反转),即从传统程序中通过直接new对象的方式转换为由spring容器创建和管理对象的生命周期。
  • DI是依赖注入(Dependency Injection),就是对象所依赖的组件由spring容器进行动态注入。
  • AOP是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。

  DI是spring对IOC的实现,通俗的说,就是程序对象之间的关系从传统实现中由程序代码直接操控转移到spring容器中,spring是通过DI来实现的,就是我们只需要告诉spring容器我们需要什么依赖,spring会进行动态注入,至于spring在什么时候将这些依赖给我们,这是spring操心的,不是我们应该操心的。于是又延伸出了另一个问题?对象需要的依赖是spring容器初始化的时候就进行注入还是使用对象的时候才进行注入的?这就是懒加载。

  我理解的spring源码加载流程图

spring 搭建 源码环境 java spring源码_AOP


  上图是我理解的spring框架流程图,其中有一个很重要的组件:PostProcessor,也叫增强器或后置处理器,主要是有来进行扩展的。spring中有BeanFactoryPostprocessor和BeanPostProcessor。BeanFactoryPostprocessor主要对BeanFactory进行扩展,一般对BeanDefinition(bean定义信息)进行扩展(如xml中"${}"的解析)。BeanPostProcessor主要对bean对象进行扩展,spring的AOP就是在BeanPostProcessor层实现的。

3.Spring如何利用反射实现对象实例化

  我们都知道Spring是通过反射实例化对象的,那spring是在那个部分使用了反射呢?
  我们先来说说java中的反射。java反射的几种方式:

  • Class.forName(“全限定名”)
  • 对象实例.getClass()
  • 类.class
      我们先来举例了反射应用场景:
public class ReflectService {

    private String name;

    public ReflectService(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "ReflectService{" +
                "name='" + name + '\'' +
                '}';
    }
}
public class ReflectController {

    private ReflectService reflectService;

    public ReflectService getReflectService() {
        return reflectService;
    }

    public void setReflectService(ReflectService reflectService) {
        this.reflectService = reflectService;
    }
}

  我们要通过反射将reflectService注入到ReflectController 中。

public void test() throws Exception {
        ReflectController reflectController = new ReflectController();

        /**
         * 反射获取Class对象的几种方式
         * 1.Class.forName("全限定名")
         * 2.对象实例.getClass()
         * 3.类.class
         */
        // spring是提供模板,而不是像这边写死
        Class<? extends ReflectController> clazz = reflectController.getClass();

        ReflectService reflectService = new ReflectService("reflect's test");

        // 获取属性
        Field serviceField = clazz.getDeclaredField("reflectService");
        //clazz.getField();
        /**
         * clazz.getDeclaredField()与clazz.getField()的区别:
         * getDeclaredField() 可以获取类本身的所有的属性成员
		 * getField() 只能获取本类及其父类的public成员
         */

        // 设置访问权限
        serviceField.setAccessible(true);

        // 通过方法设置属性
        String fieldName = serviceField.getName();

        // 拼接方法名称
        fieldName = fieldName.substring(0,1).toUpperCase() + fieldName.substring(1,fieldName.length());
        String methodName = "set" + fieldName;

        // 通过方法注入属性
        Method method = clazz.getMethod(methodName, ReflectService.class);

        // 反射调用方法
        method.invoke(reflectController,reflectService);

        // ReflectService{name='reflect's test'}
        System.out.println(reflectController.getReflectService());



    }

  上面代码是普通的反射调用(需要提供set()方法)。反射中需要要注意的就是有加Declared前缀的方法与无Declared前缀的方法的区别:Declared前缀的方法能获取本类所有修饰符修饰的属性或方法或构造器(不包括父类);无Declared前缀的方法只能获取本类及其父类的public修饰符修饰的属性或方法或构造器。
  如果我们不想提供set()方法,想实现类似于spring的@Autowrite注解注入。我们来看看下面的代码(有些方法省略部分代码)。

@Retention(RetentionPolicy.RUNTIME) // 生效阶段
@Target(ElementType.FIELD) // 作用目标
public @interface AutoField {
}
public class AnnotationController {

    @AutoField
    private ReflectService reflectService;

    public ReflectService getReflectService() {
        return reflectService;
    }
}
public void annotationTest() throws Exception {
        AnnotationController annotationController = new AnnotationController();

        /**
         * 反射获取Class对象的几种方式
         * 1.Class.forName("全限定名")
         * 2.对象实例.getClass()
         * 3.类.class
         */
        // spring是提供模板,而不是像这边写死
        Class<? extends AnnotationController> clazz = annotationController.getClass();



        // 获取所有属性
        Stream.of(clazz.getDeclaredFields()).forEach(field -> {
            String fieldName = field.getName();
            // 获取属性上的注解
            AutoField annotation = field.getAnnotation(AutoField.class);

            if(annotation != null){
                // 设置访问权限
                field.setAccessible(true);
                // 获取属性类型
                Class<?> type = field.getType();

                try {
                    /**
                     * 用构造器赋值
                     */
                    Constructor<?> constructor = type.getConstructor(String.class);
                    Object o = constructor.newInstance("reflect's annotationTest");

                    /**
                     * 不需要通过构造器赋值时,可以通过如下方式直接获取属性对象
                     * Object o = type.newInstance();
                     */
                    field.set(annotationController, o);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        });


        System.out.println(annotationController.getReflectService());



    }

  上面代码使用了Constructor进行实例化。spring中的反射也是通过Constructor进行实例化的。我们已经基本上掌握了通过java的反射实现属性注入了,下面我们来看看spring的源码。
  由于spring的源码实在太绕了,我只给出最后的代码,同时把方法调用链给大家。

//AbstractAutowireCapableBeanFactory.java
//创建bean
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
			throws BeanCreationException {

		// Instantiate the bean.
		BeanWrapper instanceWrapper = null;
		if (mbd.isSingleton()) {
			instanceWrapper = this.factoryBeanInstanceCache.remove(beanName);
		}
		if (instanceWrapper == null) {
		   //核心入口
			instanceWrapper = createBeanInstance(beanName, mbd, args);
		}
		Object bean = instanceWrapper.getWrappedInstance();
		Class<?> beanType = instanceWrapper.getWrappedClass();
		if (beanType != NullBean.class) {
			mbd.resolvedTargetType = beanType;
		}

		// Allow post-processors to modify the merged bean definition.
		synchronized (mbd.postProcessingLock) {
			if (!mbd.postProcessed) {
				try {
					applyMergedBeanDefinitionPostProcessors(mbd, beanType, beanName);
				}
				catch (Throwable ex) {
					throw new BeanCreationException(mbd.getResourceDescription(), beanName,
							"Post-processing of merged bean definition failed", ex);
				}
				mbd.postProcessed = true;
			}
		}

		/**
		 * 主动缓存单例,以便能够解析循环引用
		 * 即使被BeanFactoryAware这样的生命周期接口触发。
		 */

		// Eagerly cache singletons to be able to resolve circular references
		// even when triggered by lifecycle interfaces like BeanFactoryAware.
		boolean earlySingletonExposure = (mbd.isSingleton() && this.allowCircularReferences &&
				isSingletonCurrentlyInCreation(beanName));
		if (earlySingletonExposure) {
			if (logger.isTraceEnabled()) {
				logger.trace("Eagerly caching bean '" + beanName +
						"' to allow for resolving potential circular references");
			}
			//添加缓存
			addSingletonFactory(beanName, () -> getEarlyBeanReference(beanName, mbd, bean));
		}

		// Initialize the bean instance.
		Object exposedObject = bean;
		try {
			//填充属性
			populateBean(beanName, mbd, instanceWrapper);
			exposedObject = initializeBean(beanName, exposedObject, mbd);
		}
		catch (Throwable ex) {
			if (ex instanceof BeanCreationException && beanName.equals(((BeanCreationException) ex).getBeanName())) {
				throw (BeanCreationException) ex;
			}
			else {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Initialization of bean failed", ex);
			}
		}

		if (earlySingletonExposure) {
			Object earlySingletonReference = getSingleton(beanName, false);
			if (earlySingletonReference != null) {
				if (exposedObject == bean) {
					exposedObject = earlySingletonReference;
				}
				else if (!this.allowRawInjectionDespiteWrapping && hasDependentBean(beanName)) {
					String[] dependentBeans = getDependentBeans(beanName);
					Set<String> actualDependentBeans = new LinkedHashSet<>(dependentBeans.length);
					for (String dependentBean : dependentBeans) {
						if (!removeSingletonIfCreatedForTypeCheckOnly(dependentBean)) {
							actualDependentBeans.add(dependentBean);
						}
					}
					if (!actualDependentBeans.isEmpty()) {
						throw new BeanCurrentlyInCreationException(beanName,
								"Bean with name '" + beanName + "' has been injected into other beans [" +
								StringUtils.collectionToCommaDelimitedString(actualDependentBeans) +
								"] in its raw version as part of a circular reference, but has eventually been " +
								"wrapped. This means that said other beans do not use the final version of the " +
								"bean. This is often the result of over-eager type matching - consider using " +
								"'getBeanNamesForType' with the 'allowEagerInit' flag turned off, for example.");
					}
				}
			}
		}

		// Register bean as disposable.
		try {
			registerDisposableBeanIfNecessary(beanName, bean, mbd);
		}
		catch (BeanDefinitionValidationException ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Invalid destruction signature", ex);
		}

		return exposedObject;
	}
//
    //根据特定的bean及实例化策略创建一个bean实例
	protected BeanWrapper createBeanInstance(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) {
		// 根据beanName解析出对象的Class,类似于Class.forName("全限定名")
		Class<?> beanClass = resolveBeanClass(mbd, beanName);

		if (beanClass != null && !Modifier.isPublic(beanClass.getModifiers()) && !mbd.isNonPublicAccessAllowed()) {
			throw new BeanCreationException(mbd.getResourceDescription(), beanName,
					"Bean class isn't public, and non-public access not allowed: " + beanClass.getName());
		}

		Supplier<?> instanceSupplier = mbd.getInstanceSupplier();
		if (instanceSupplier != null) {
			return obtainFromSupplier(instanceSupplier, beanName);
		}

		if (mbd.getFactoryMethodName() != null) {
			return instantiateUsingFactoryMethod(beanName, mbd, args);
		}

		// Shortcut when re-creating the same bean...
		boolean resolved = false;
		boolean autowireNecessary = false;
		if (args == null) {
			synchronized (mbd.constructorArgumentLock) {
				if (mbd.resolvedConstructorOrFactoryMethod != null) {
					resolved = true;
					autowireNecessary = mbd.constructorArgumentsResolved;
				}
			}
		}
		if (resolved) {
			if (autowireNecessary) {
				return autowireConstructor(beanName, mbd, null, null);
			}
			else {
				return instantiateBean(beanName, mbd);
			}
		}

		// Candidate constructors for autowiring?
		Constructor<?>[] ctors = determineConstructorsFromBeanPostProcessors(beanClass, beanName);
		if (ctors != null || mbd.getResolvedAutowireMode() == AUTOWIRE_CONSTRUCTOR ||
				mbd.hasConstructorArgumentValues() || !ObjectUtils.isEmpty(args)) {
			return autowireConstructor(beanName, mbd, ctors, args);
		}

		// Preferred constructors for default construction?
		ctors = mbd.getPreferredConstructors();
		if (ctors != null) {
		    //如果是通过有参构造器进行属性注入,走该分支(不详细分析,因为最终都是通过BeanUtils的instantiateClass()进行实例化的)
			return autowireConstructor(beanName, mbd, ctors, null);
		}

		// No special handling: simply use no-arg constructor.
		//使用无参构造器进行实例化
		return instantiateBean(beanName, mbd);
	}
//AbstractAutowireCapableBeanFactory.java
	 //通过构造器实例化给定的bean
	protected BeanWrapper instantiateBean(String beanName, RootBeanDefinition mbd) {
			……
			else {
			    //创建bean实例
				beanInstance = getInstantiationStrategy().instantiate(mbd, beanName, this);
			}
			BeanWrapper bw = new BeanWrapperImpl(beanInstance);
			initBeanWrapper(bw);
			return bw;
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					mbd.getResourceDescription(), beanName, "Instantiation of bean failed", ex);
		}
	}
//SimpleInstantiationStrategy.java
	//实例化
	@Override
	public Object instantiate(RootBeanDefinition bd, @Nullable String beanName, BeanFactory owner) {
		// Don't override the class with CGLIB if no overrides.
		if (!bd.hasMethodOverrides()) {
			Constructor<?> constructorToUse;
			synchronized (bd.constructorArgumentLock) {
				constructorToUse = (Constructor<?>) bd.resolvedConstructorOrFactoryMethod;
				if (constructorToUse == null) {
					final Class<?> clazz = bd.getBeanClass();
					if (clazz.isInterface()) {
						throw new BeanInstantiationException(clazz, "Specified class is an interface");
					}
					try {
						if (System.getSecurityManager() != null) {
							constructorToUse = AccessController.doPrivileged(
									(PrivilegedExceptionAction<Constructor<?>>) clazz::getDeclaredConstructor);
						}
						else {
							//反射获取构造器
							constructorToUse = clazz.getDeclaredConstructor();
						}
						bd.resolvedConstructorOrFactoryMethod = constructorToUse;
					}
					catch (Throwable ex) {
						throw new BeanInstantiationException(clazz, "No default constructor found", ex);
					}
				}
			}
			return BeanUtils.instantiateClass(constructorToUse);
		}
		else {
			// Must generate CGLIB subclass.
			return instantiateWithMethodInjection(bd, beanName, owner);
		}
	}
//BeanUtils.java
	public static <T> T instantiateClass(Constructor<T> ctor, Object... args) throws BeanInstantiationException {
		Assert.notNull(ctor, "Constructor must not be null");
		try {
			ReflectionUtils.makeAccessible(ctor);
			if (KotlinDetector.isKotlinReflectPresent() && KotlinDetector.isKotlinType(ctor.getDeclaringClass())) {
				return KotlinDelegate.instantiateClass(ctor, args);
			}
			else {
				Class<?>[] parameterTypes = ctor.getParameterTypes();
				Assert.isTrue(args.length <= parameterTypes.length, "Can't specify more arguments than constructor parameters");
				Object[] argsWithDefaultValues = new Object[args.length];
				for (int i = 0 ; i < args.length; i++) {
					if (args[i] == null) {
						Class<?> parameterType = parameterTypes[i];
						argsWithDefaultValues[i] = (parameterType.isPrimitive() ? DEFAULT_TYPE_VALUES.get(parameterType) : null);
					}
					else {
						argsWithDefaultValues[i] = args[i];
					}
				}
				//反射创建对象
				return ctor.newInstance(argsWithDefaultValues);
			}
		}
		catch (InstantiationException ex) {
			throw new BeanInstantiationException(ctor, "Is it an abstract class?", ex);
		}
		catch (IllegalAccessException ex) {
			throw new BeanInstantiationException(ctor, "Is the constructor accessible?", ex);
		}
		catch (IllegalArgumentException ex) {
			throw new BeanInstantiationException(ctor, "Illegal arguments for constructor", ex);
		}
		catch (InvocationTargetException ex) {
			throw new BeanInstantiationException(ctor, "Constructor threw exception", ex.getTargetException());
		}
	}

  最后我们跟踪到了ctor.newInstance(argsWithDefaultValues);即通过反射调用构造器创建对象实例。

  方法调用链如下:

spring 搭建 源码环境 java spring源码_java反射_02


  在实例化完成后,spring会将单例的bean实例缓存起来,下次获取的时候先去缓存中找(context.getBean()),找不再进行实例化。

4.Spring如何利用动态代理实现AOP

  AOP是面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP利用一种称为“横切”的技术,剖解开封装的对象内部,并将那些影响了 多个类的公共行为封装到一个可重用模块,并将其名为“Aspect”,即方面。所谓“方面”,简单地说,就是将那些与业务无关,却为业务模块所共同调用的 逻辑或责任封装起来,比如日志记录,便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可操作性和可维护性。
  Spring实现AOP:JDK动态代理和CGLIB代理 JDK动态代理:其代理对象必须是某个接口的实现,它是通过在运行期间创建一个接口的实现类来完成对目标对象的代理;其核心的两个类是InvocationHandler和Proxy。 CGLIB代理:实现原理类似于JDK动态代理,只是它在运行期间生成的代理对象是针对目标类扩展的子类。CGLIB是高效的代码生成包,底层是依靠ASM(开源的java字节码编辑类库)操作字节码实现的,性能比JDK强;需要引入包asm.jar和cglib.jar。
  Spring中有许多AOP的应用场景如:Authentication 权限检查及Transactions 事务管理等 。
4.1 JDK动态代理
  Jdk动态代理:利用拦截器(必须实现InvocationHandler)加上反射机制生成一个代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。Jdk动态代理是基于接口代理的,下面来看一般实现JDK动态代理的代码。

public interface UserService {

    void getUserNameById(Integer uid);

    void insertUser(String userName);
    
    void innerProxy();
}

public class UserServiceImpl implements UserService{
    @Override
    public void getUserNameById(Integer uid) {
        System.out.println("获取用户成功[uid = " + uid + "]");
    }

    @Override
    public void insertUser(String userName) {
        System.out.println("保存成功[userName = " + userName + "]");
    }
    
    @Override
    public void innerProxy(){
        /**
         * 无法执行代理中的代码,相当于this.getUserNameById(0),
         * 不是通过代理对象执行getUserNameById(0),所以未执行invoke()中的操作
         */
        getUserNameById(0);
    }
}


public class JdkInvocationHandler implements InvocationHandler {

    //目标类
    private Object targetObj;

    public JdkInvocationHandler(Object targetObj) {
        this.targetObj = targetObj;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        String name = method.getName();

        System.out.println("method = " + name + ", args = " + Arrays.deepToString(args));
        System.out.println("方法" + name + "执行前(doSomeThing)……");


        Object returnValue = method.invoke(targetObj, args);

        System.out.println("方法" + name + "执行后(doSomeThing)……");

        return returnValue;
    }
}

public class ProxyTest {

    public static void main(String[] args) {
        
        //代理类UserServiceImpl
        UserService userService = new UserServiceImpl();

        InvocationHandler jdkInvocationHandler = new JdkInvocationHandler(userService);

        UserService proxyUserService = (UserService)Proxy.newProxyInstance(ProxyTest.class.getClassLoader(), new Class<?>[]{UserService.class}, jdkInvocationHandler);

        proxyUserService.getUserNameById(1);
        proxyUserService.insertUser("zhangli");

		System.out.println("++++++++++++++++++++++++++++++++++++++++");

        proxyUserService.innerProxy();
     
    }
}

  执行结果:

method = getUserNameById, args = [1]
方法getUserNameById执行前(doSomeThing)……
获取用户成功[uid = 1]
方法getUserNameById执行后(doSomeThing)……
method = insertUser, args = [zhangli]
方法insertUser执行前(doSomeThing)……
保存成功[userName = zhangli]
方法insertUser执行后(doSomeThing)……
++++++++++++++++++++++++++++++++++++++++
method = innerProxy, args = null
方法innerProxy执行前(doSomeThing)……
获取用户成功[uid = 0]
方法innerProxy执行后(doSomeThing)……

  需要注意的是innerProxy()这个方法,我在方法的内部又调用了getUserNameById(0);按照我们的正常理解来说应该会打印两次方法执行前和方法执行后。其实并不是。

@Override
    public void innerProxy(){
        /**
         * 无法执行代理中的代码,相当于this.getUserNameById(0),
         * 不是通过代理对象执行getUserNameById(0),所以未执行invoke()中的操作
         * 
         * 延伸:spring中的嵌套事务
         * 我们都知道Spring中的事务是通过AOP实现的,所以有嵌套事务的时候,我们应该先获取当前的
         * 代理对象,再通过代理对象来调用方法。而不是直接调用(this调用方法)
         */
        getUserNameById(0);
    }

4.2 cglib动态代理
  Cglib动态代理利用ASM框架,将代理对象类生成的class文件加载进来,通过修改其字节码生成子类来处理。
  首先引入相关依赖

<dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.1</version>
        </dependency>
public class ProductService {

    public void getProductBy(Integer id){
        System.out.println("获取产品成功[uid = " + id + "]");
    }

    public void innerProxy(Integer id){
        System.out.println("ProductService's innerProxy ……");
        getProductBy(id);
    }
}


public class CglibMethodInterceptor implements MethodInterceptor {
    
    //方法拦截
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {

        System.out.println("方法" + method.getName() + "执行前(doSomeThing)……");

        Object invoke = methodProxy.invokeSuper(o, objects);
        System.out.println("方法" + method.getName() + "执行后(doSomeThing)……");

        return invoke;
    }
}


public class ProxyTest {

    public static void main(String[] args) {

        //增强器
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(ProductService.class);
        enhancer.setCallback(new CglibMethodInterceptor());
        ProductService productService = (ProductService)enhancer.create();
        productService.innerProxy(1);

        System.out.println("++++++++++++++++++++++++++++++++++++++++");
        Enhancer enhancer1 = new Enhancer();
        enhancer1.setSuperclass(UserServiceImpl.class);
        enhancer1.setCallback(new CglibMethodInterceptor());
        UserService proxyUserService = (UserService)enhancer1.create();
        proxyUserService.getUserNameById(0);
        proxyUserService.innerProxy();
    }

  执行结果:

方法innerProxy执行前(doSomeThing)……
ProductService's innerProxy ……
方法getProductBy执行前(doSomeThing)……
获取产品成功[uid = 1]
方法getProductBy执行后(doSomeThing)……
方法innerProxy执行后(doSomeThing)……
++++++++++++++++++++++++++++++++++++++++
方法getUserNameById执行前(doSomeThing)……
获取用户成功[uid = 0]
方法getUserNameById执行后(doSomeThing)……
方法innerProxy执行前(doSomeThing)……
方法getUserNameById执行前(doSomeThing)……
获取用户成功[uid = 0]
方法getUserNameById执行后(doSomeThing)……
方法innerProxy执行后(doSomeThing)……

  从代码执行结果可以看出,cglib既可以代理接口,也可以代理类,而且没有java动态代理方法嵌套调用的问题。

4.3 spring中的动态代理

  什么时候用cglib什么时候用jdk动态代理?

  • 目标对象生成了接口 默认用JDK动态代理
  • 如果目标对象使用了接口,可以强制使用cglib
  • 如果目标对象没有实现接口,必须采用cglib库,Spring会自动在JDK动态代理和cglib之间转换

  JDK动态代理和cglib字节码生成的区别?

  • JDK动态代理只能对实现了接口的类生成代理,而不能针对类
  • Cglib是针对类实现代理,主要是对指定的类生成一个子类,覆盖其中的方法,并覆盖其中方法的增强,但是因为采用的是继承,所以该类或方法最好不要生成final,对于final类或方法,是无法继承的

SpringAOP功能的实现

//ProxyFactoryBean.java
	private synchronized Object getSingletonInstance() {
		if (this.singletonInstance == null) {
			this.targetSource = freshTargetSource();
			if (this.autodetectInterfaces && getProxiedInterfaces().length == 0 && !isProxyTargetClass()) {
				// Rely on AOP infrastructure to tell us what interfaces to proxy.
				Class<?> targetClass = getTargetClass();
				if (targetClass == null) {
					throw new FactoryBeanNotInitializedException("Cannot determine target class for proxy");
				}
				setInterfaces(ClassUtils.getAllInterfacesForClass(targetClass, this.proxyClassLoader));
			}
			// Initialize the shared singleton instance.
			super.setFrozen(this.freezeProxy);
			this.singletonInstance = getProxy(createAopProxy());
		}
		return this.singletonInstance;
	}
//ProxyCreatorSupport.java
	protected final synchronized AopProxy createAopProxy() {
		if (!this.active) {
			activate();
		}
		return getAopProxyFactory().createAopProxy(this);
	}
//DefaultAopProxyFactory.java
@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (!IN_NATIVE_IMAGE &&
				(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)) {
				return new JdkDynamicAopProxy(config);
			}
			//cglib代理
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			//jdk代理
			return new JdkDynamicAopProxy(config);
		}
	}

5.代码实践

  下面是我结合java反射和jdk动态代理模仿mybatis解析sql的代码。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Query {
    String value();
}
interface UserMapper{
    @Query("select * from t_user where name={#name} and age={#age}")
    List queryUserByNameAndAge(String name, Integer age);

    @Query("select * from t_user where name={#name}")
    List queryUserByName(String name);
}


public class MyMybatis {

    public static void main(String[] args) {

        UserMapper userMapper = (UserMapper) Proxy.newProxyInstance(MyMybatis.class.getClassLoader(), new Class<?>[]{UserMapper.class}, new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                //获取注解
                Query annotation = method.getAnnotation(Query.class);

                //创建一个map,存储方法参数
                Map<String, Object> argNameMap = buildMethodArgNameMap(method, args);
                if(annotation != null){
                    String value = annotation.value();
                    System.out.println("annotationValue = " + value);
                    String sql = parseSql(value, argNameMap);
                    System.out.println("sql = " + sql);
                }


                return null;
            }
        });
        userMapper.queryUserByNameAndAge("zhangli",18);
        userMapper.queryUserByName("zhangli");
    }

   /**
     * 将注解上的mybatis类型的sql解析成可执行的sql语句
     * @param sql
     * @param argNameMap
     * @return
     */
    private static String parseSql(String sql, Map<String, Object> argNameMap) {

        StringBuffer sb = new StringBuffer();

        int beginIndex = 0;

        //解析注解中的sql语句中的占位符
        parseSqlPlaceholder(sql,argNameMap,beginIndex,sb);


        return sb.toString();
    }

    /**
     * 注解中的sql语句中的占位符替换成参数
     * @param sql
     * @param argNameMap
     * @param beginIndex
     * @param sb
     */
    private static void parseSqlPlaceholder(String sql, Map<String, Object> argNameMap, int beginIndex, StringBuffer sb) {


        //将sql注解中的占位符替换成参数值
        //例如:select * from t_user where name={#name} and age={#age}将{#name}和{#age}替换成接口传进来的参数
        while (beginIndex >= 0 && beginIndex < sql.length()){
            char c = sql.charAt(beginIndex);
            if(c == '{'){
                beginIndex = replacePlaceholder(sql, argNameMap, sb, beginIndex);
            }else {
                sb.append(c);
            }

            beginIndex ++;
        }

    }

    /**
     * 将占位符替换成参数值
     * @param sql
     * @param argNameMap
     * @param sb
     * @param index
     * @return
     */
    private static int replacePlaceholder(String sql, Map<String, Object> argNameMap, StringBuffer sb,int index) {
        int begin = index + 1;
        int finalIndex = -1;
        //是否有结束标签'}'
        boolean hasEnd = false;
        if(sql.charAt(begin) != '#'){
            throw new RuntimeException("sql格式不正确:" + sql + "(index:" + begin + ")");
        }
        StringBuffer stringBuffer = new StringBuffer();
        for(int i = begin+1;i < sql.length(); i ++){
            char c = sql.charAt(i);
            if(c != '}' && c != ' '){
                stringBuffer.append(c);
            }else {
                if(c == ' '){
                    throw new RuntimeException("sql格式不正确(参数中不能包含空格):" + sql + "(index:" + i + ")");
                }
                //记录'}'的位置,作为查找下一个参数替换的起始值
                finalIndex = i;
                hasEnd = true;
                break;
            }
        }
        //如果没有结束标签
        if(!hasEnd){
            throw new RuntimeException("sql格式不正确:" + sql + "(未正常结束)");
        }
        String arg = stringBuffer.toString();

        Object o = argNameMap.get(arg);
        if(o == null){
            throw new RuntimeException("sql:"+sql+"("+"无法配置到参数" + arg + "对应的值)");
        }
        //获取参数类型
        String typeName = o.getClass().getTypeName();
        //根据不同的参数类型组装sql,只判断了String及Integer类型,其他类型处理类似
        if(typeName.equals("java.lang.String")){
            char fix = '\'';
            sb.append(fix);
            sb.append((String) o);
            sb.append(fix);
        }
        if(typeName.equals("java.lang.Integer")){
            sb.append((Integer) o);
        }

        return finalIndex;

    }

    /**
     * 构建方法参数Map,Map<参数名,参数值>,方便后续解析时根据占位符中的参数名找到对应的参数值
     * @param method
     * @param args
     * @return
     */
    private static Map<String,Object> buildMethodArgNameMap(Method method, Object[] args) {
        Map<String,Object> map = new HashMap<>();
        // 获取方法参数
        Parameter[] parameters = method.getParameters();
        //从lambda 表达式引用的本地变量必须是最终变量或实际上的最终变量(类似内部类引用本地变量)
        //可以通过如下方式实现在lambda表达式int类型自增
        int index[] = {0};
        Arrays.asList(parameters).forEach(parameter -> {
            String name = parameter.getName();
            System.out.println("methodName = " + name);
            map.put(name, args[index[0]]);
            index[0] ++;
        });

        return map;
    }
}

执行结果

methodName = name
methodName = age
annotationValue = select * from t_user where name={#name} and age={#age}
sql = select * from t_user where name='zhangli' and age=18
methodName = name
annotationValue = select * from t_user where name={#name}
sql = select * from t_user where name='zhangli'