spring(ioc/aop)

102 阅读10分钟

前言

  • 教程:spring ioc和aop理解
  • 时间:2021/11/5
  • 整理人:vanse
  • 环境:jdk8 spring5.2
  • 参考: 马士兵(ioc) briup(aop)

ioc理解

理论

spring源码概览

该声明周期在BeanFactory中有规定

	* <p>Bean factory implementations should support the standard bean lifecycle interfaces
 * as far as possible. The full set of initialization methods and their standard order is:
 * <ol>
 * <li>BeanNameAware's {@code setBeanName}
 * <li>BeanClassLoaderAware's {@code setBeanClassLoader}
 * <li>BeanFactoryAware's {@code setBeanFactory}
 * <li>EnvironmentAware's {@code setEnvironment}
 * <li>EmbeddedValueResolverAware's {@code setEmbeddedValueResolver}
 * <li>ResourceLoaderAware's {@code setResourceLoader}
 * (only applicable when running in an application context)
 * <li>ApplicationEventPublisherAware's {@code setApplicationEventPublisher}
 * (only applicable when running in an application context)
 * <li>MessageSourceAware's {@code setMessageSource}
 * (only applicable when running in an application context)
 * <li>ApplicationContextAware's {@code setApplicationContext}
 * (only applicable when running in an application context)
 * <li>ServletContextAware's {@code setServletContext}
 * (only applicable when running in a web application context)
 * <li>{@code postProcessBeforeInitialization} methods of BeanPostProcessors
 * <li>InitializingBean's {@code afterPropertiesSet}
 * <li>a custom init-method definition
 * <li>{@code postProcessAfterInitialization} methods of BeanPostProcessors
 * </ol>

BeanPostProcessor和BeanFactoryPostProcessor (后置处理器/增强器)

  • BeanFactoryPostProcessor 增强BeanDefinition
  • BeanPostProcessor 增强Bean信息

Spring Bean

  • 普通对象 自定义对象(我们需要)
  • 容器对象 内置对象 (spring需要)

BeanFactory和FactoryBean

  • BeanFactory spring控制
  • FactoryBean 用户控制 无须遵循bean的生命周期
    • &user 取工厂对象
    • user 取user对象

实操

实体类

public class Customer implements InitializingBean, BeanFactoryAware, BeanNameAware, DisposableBean {
	private String name;

	private String beanName;
	private BeanFactory beanFactory;

	public Customer() {
		System.out.println("【customer】的无参构造器");
	}
	// 这是BeanNameAware接口方法
	@Override
	public void setBeanName(String beanName) {
		System.out.println("【BeanNameAware接口】调用BeanNameAware.setBeanName()");
		this.beanName = beanName;
	}
	// 这是BeanFactoryAware接口方法
	@Override
	public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
		System.out.println("【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()");
		this.beanFactory = beanFactory;
	}
	// 这是InitializingBean接口方法
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("【InitializingBean接口】调用InitializingBean.afterPropertiesSet()");
	}

	// 这是DiposibleBean接口方法
	@Override
	public void destroy() throws Exception {
		System.out.println("【DiposibleBean接口】调用DiposibleBean.destory()");
	}
	// 通过<bean>的init-method属性指定的初始化方法
	public void myInit() {
		System.out.println("【init-method】调用<bean>的init-method属性指定的初始化方法");
	}
	// 通过<bean>的destroy-method属性指定的销毁方法
	public void myDestory() {
		System.out.println("【destroy-method】调用<bean>的destroy-method属性指定的销毁方法");
	}

	public String getName() {
		System.out.println("【person】 注入属性 name");
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
	@Override
	public String toString() {
		return "Customer [name=" + name + ", beanName=" + beanName + ", beanFactory=" + beanFactory + "]";
	}
}

MyBeanFactoryPostProcessor

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
// 后置处理器 可干预BeanDefinition
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    public MyBeanFactoryPostProcessor() {
        System.out.println("【BeanFactoryPostProcessor】构造器!!");
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory factory)
            throws BeansException {
        System.out
                .println("BeanFactoryPostProcessor调用postProcessBeanFactory方法");
        BeanDefinition bd = factory.getBeanDefinition("customer");
        bd.getPropertyValues().addPropertyValue("name", "vanse");
    }
}

后置处理器 可干预BeanDefinition


MyInstantitationAwareBeanPostProcessor 实例化处理器

import java.beans.PropertyDescriptor;

import org.springframework.beans.BeansException;
import org.springframework.beans.PropertyValues;
import org.springframework.beans.factory.config.InstantiationAwareBeanPostProcessor;
public class MyInstantitationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
	MyInstantitationAwareBeanPostProcessor(){
		System.out.println("【MyInstantitationAwareBeanPostProcessor】构造方法");
	}
	// 实例化前是beanClass
	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		if("customer".equals(beanName)) {
			System.out.println("实例化前");
		}
		return InstantiationAwareBeanPostProcessor.super.postProcessBeforeInstantiation(beanClass, beanName);
	}
	// 实例化后 是bean
	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		if("customer".equals(beanName)) {
			System.out.println("实例化后");
		}
		return InstantiationAwareBeanPostProcessor.super.postProcessAfterInstantiation(bean, beanName);
	}
	@Override
	public PropertyValues postProcessPropertyValues(PropertyValues pvs, PropertyDescriptor[] pds, Object bean,
			String beanName) throws BeansException {
		if("customer".equals(beanName)) {
			System.out.println("实例化中设置属性");
		}
		return InstantiationAwareBeanPostProcessor.super.postProcessPropertyValues(pvs, pds, bean, beanName);
	}
}

MyBeanPostProcessor

后置处理器 可干预bean

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class MyBeanPostProcessor implements BeanPostProcessor{
	public MyBeanPostProcessor() {
		System.out.println("【MyBeanPostProcessor】构造方法");
	}
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if("customer".equals(beanName)) {
			System.out.println("初始化前");
		}
		return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if("customer".equals(beanName)) {
			System.out.println("初始化后");
		}
		return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
	}
}

bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:p="http://www.springframework.org/schema/p"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

	<bean id="beanPostProcessor"
		class="com.briup.life.process.MyBeanPostProcessor">
	</bean>

	<bean id="instantiationAwareBeanPostProcessor"
		class="com.briup.life.process.MyInstantitationAwareBeanPostProcessor">
	</bean>

	<bean id="beanFactoryPostProcessor"
		class="com.briup.life.process.MyBeanFactoryPostProcessor">
	</bean>

	<bean id="customer" class="com.briup.life.entity.Customer"
		init-method="myInit" destroy-method="myDestory" scope="singleton">
		<property name="name" value="tom"></property>
	</bean>

</beans>

测试

public class TestLife {
	public static void main(String[] args) {
		System.out.println("现在开始初始化容器");
		ClassPathXmlApplicationContext context 
		   = new ClassPathXmlApplicationContext("bean.xml");
		System.out.println("容器初始化成功");   
		Customer customer = (Customer) context.getBean("customer");
		System.out.println(customer);
		System.out.println("现在开始关闭容器!");
		context.close();
	}
}

结果

现在开始初始化容器

【BeanFactoryPostProcessor】构造器!!
BeanFactoryPostProcessor调用postProcessBeanFactory方法
【MyBeanPostProcessor】构造方法
【MyInstantitationAwareBeanPostProcessor】构造方法
实例化前
【customer】的无参构造器
实例化后
实例化中设置属性
【BeanNameAware接口】调用BeanNameAware.setBeanName()
【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()
初始化前
【InitializingBean接口】调用InitializingBean.afterPropertiesSet()
【init-method】调用<bean>的init-method属性指定的初始化方法
初始化后

容器初始化成功
Customer [name=vanse, beanName=customer, beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@10d59286: defining beans [beanPostProcessor,instantiationAwareBeanPostProcessor,beanFactoryPostProcessor,customer]; root of factory hierarchy]

现在开始关闭容器!
【DiposibleBean接口】调用DiposibleBean.destory()
【destroy-method】调用<bean>的destroy-method属性指定的销毁方法

总结

  • BeanFactoryPostProcessor 后置设置BeanDefinition
  • instantiationAwareBeanPostProcessor 实例化前
  • Customer 推断构造方法 创建调用
  • instantiationAwareBeanPostProcessor 实例化后
  • instantiationAwareBeanPostProcessor 实例化后设置属性
  • BeanNameAware接口
  • BeanFactoryAware接口
  • beanPostProcessor 初始化前
  • InitializingBean接口 初始化
  • init-method 初始化方法
  • beanPostProcessor 初始化后
  • DiposibleBean 销毁
  • destroy-method 销毁方法

aop理解

代理

代理模式是一种常见的设计模式,它提供间接对目标对象访问的方式,通过代理对象访问目标对象,从而在在目标对象现有的功能能上,增加额外的功能补充,实现扩展目标对象的功能

静态代理

静态代理是代理模式的实现方式之一,在程序运行前,手动创建代理类,从而实现对目标类中的方法进行增强

IUserService

public interface IUserService {
	void login();
}

UserServiceImpl

public class UserServiceImpl implements IUserService{

	@Override
	public void login() {
		System.out.println("模拟 用户登录");
	}
}

TestStaticProxy

// 不使用代理 功能有限
	@Test
	public void test() {
		IUserService userService = new UserServiceImpl();
		userService.login();
	}

UserServiceProxy

// 代理类
	// 必须含有原方法
	// 再增强方法
public class UserServiceProxy implements IUserService{
	private UserServiceImpl userServiceImpl;
	public UserServiceProxy(UserServiceImpl userServiceImpl) {
		this.userServiceImpl = userServiceImpl;
	}
	@Override
	public void login() {
		System.out.println("访问前时间");
		//System.out.println("用户登录");
		userServiceImpl.login();
		System.out.println("访问后时间");
	}
	
}

TestStaticProxy

// 将来spring 自动注入 @Autowired
	@Test
	public void test2() {
		UserServiceImpl userServiceImpl = new UserServiceImpl();
		IUserService userService = new UserServiceProxy(userServiceImpl);
		userService.login();
	}

动态代理

动态代理则是在程序运行期间,采用字节码技术,动态生成的一个代理对象,从而实现目标对象中方法的增强

jdk

Proxy类中的newProxyInstance 方法,可以在运行启动期间,动态生成指定接口的代理类对象:

public class Proxy implements java.io.Serializable {
 	/**
    * loader,目标类的类加载器
    * interfaces,目标类所实现的接口,可以是多个
    * InvocationHandler,InvocationHandler接口的实现类对象
    */
    public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)throws IllegalArgumentException{
    //...增强哪些方法
    }   
}

java.lang.reflect.InvocationHandler 接口中只有一个抽象方法:

package java.lang.reflect;
public interface InvocationHandler {
    /**
    * proxy,将来动态生成的代理类对象
    * method,将来需要代理的目标对象中的方法
    * args,将来调用目标对象方法时所传入的参数列表
    */
    public Object invoke(Object proxy, Method method, Object[] args)throws Throwable;
}

ICustomerService

public interface ICustomerService {
	void login();
}

CustomerServiceImpl

public class CustomerServiceImpl implements ICustomerService{

	@Override
	public void login() {
		System.out.println("模拟顾客登录");
	}
	
}

TestJDKProxy

public class TestJDKProxy {
	@Test
	public void test() {
		ICustomerService customerServcie = new CustomerServiceImpl();
		customerServcie.login();
	}
	
	@Test
	public void test1() {
		CustomerServiceImpl customerServcie = new CustomerServiceImpl();
		 ICustomerService proxy = (ICustomerService) Proxy.newProxyInstance(
				customerServcie.getClass().getClassLoader(),
				customerServcie.getClass().getInterfaces() , 
				new InvocationHandler() {
					@Override
					public Object invoke(Object object, Method method, Object[] arg) throws Throwable {
						System.out.println("记录时间前");
						Object result = method.invoke(customerServcie, arg);
						System.out.println("记录时间后");
						return result;
					}
				});
		 proxy.login();
	}
}

反编译

/*
 * Decompiled with CFR.
 *
 * Could not load the following classes:
 *  com.briup.aop.proxy.dproxy.jdk.ICustomerService
 */
package com.sun.proxy;

import com.briup.aop.proxy.dproxy.jdk.ICustomerService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;

public final class $Proxy0
extends Proxy
implements ICustomerService {
    private static Method m1;
    private static Method m2;
    private static Method m3;
    private static Method m0;

    public $Proxy0(InvocationHandler invocationHandler) {
        super(invocationHandler);
    }

    static {
        try {
            m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
            m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
            m3 = Class.forName("com.briup.aop.proxy.dproxy.jdk.ICustomerService").getMethod("login", new Class[0]);
            m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
            return;
        }
        catch (NoSuchMethodException noSuchMethodException) {
            throw new NoSuchMethodError(noSuchMethodException.getMessage());
        }
        catch (ClassNotFoundException classNotFoundException) {
            throw new NoClassDefFoundError(classNotFoundException.getMessage());
        }
    }

    public final boolean equals(Object object) {
        try {
            return (Boolean)this.h.invoke(this, m1, new Object[]{object});
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString() {
        try {
            return (String)this.h.invoke(this, m2, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode() {
        try {
            return (Integer)this.h.invoke(this, m0, null);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final void login() {
        try {
            this.h.invoke(this, m3, null);
            return;
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }
}

cglib

CGLIB通过ASM动态操作指令,生成了被代理类的子类,如果目标类是final修饰的,则不能够被代理

BookServiceImpl

public class BookServiceImpl {
	public void findAll() {
		System.out.println("查书");
	}
}

TestCglib

public class TestCglib {
	@Test
	public void test() {
		BookServiceImpl bookService = new BookServiceImpl();
		bookService.findAll();
	}
	
	@Test
	public void test2() {
		Enhancer enhancer = new Enhancer();
		enhancer.setSuperclass(BookServiceImpl.class);
//		enhancer.setCallback(new MethodInterceptor() {
//			@Override
//			public Object intercept(Object object, Method method, Object[] arg, MethodProxy methodProxy) throws Throwable {
//				System.out.println(method.getName());
//				System.out.println(methodProxy);
//				System.out.println("查询时间前");
//				Object result = methodProxy.invokeSuper(object, arg);
//				System.out.println("查询时间后");
//				return result;
//			}
//		});
		BookServiceImpl bookService = new BookServiceImpl();
		enhancer.setCallback(new InvocationHandler() {
			@Override
			public Object invoke(Object object, Method method, Object[] arg) throws Throwable {
				System.out.println("查询时间前");
				Object result = method.invoke(bookService, arg);
				System.out.println("查询时间后");
				return result;
			}
		});
		
		BookServiceImpl proxy = (BookServiceImpl) enhancer.create();
		proxy.findAll();
	}
}

反编译

/*
 * Decompiled with CFR.
 *
 * Could not load the following classes:
 *  com.briup.aop.proxy.dproxy.cglib.BookServiceImpl
 */
package com.briup.aop.proxy.dproxy.cglib;

import com.briup.aop.proxy.dproxy.cglib.BookServiceImpl;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Callback;
import org.springframework.cglib.proxy.Factory;
import org.springframework.cglib.proxy.InvocationHandler;
import org.springframework.cglib.proxy.UndeclaredThrowableException;

public class BookServiceImpl$$EnhancerByCGLIB$$b0c38b85
extends BookServiceImpl
implements Factory {
    private boolean CGLIB$BOUND;
    public static Object CGLIB$FACTORY_DATA;
    private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
    private static final Callback[] CGLIB$STATIC_CALLBACKS;
    private InvocationHandler CGLIB$CALLBACK_0;
    private static Object CGLIB$CALLBACK_FILTER;
    private static final Method CGLIB$findAll$0;
    private static final Method CGLIB$equals$1;
    private static final Method CGLIB$toString$2;
    private static final Method CGLIB$hashCode$3;
    private static final Method CGLIB$clone$4;

    public BookServiceImpl$$EnhancerByCGLIB$$b0c38b85() {
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85 bookServiceImpl$$EnhancerByCGLIB$$b0c38b85 = this;
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$BIND_CALLBACKS(bookServiceImpl$$EnhancerByCGLIB$$b0c38b85);
    }

    static {
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$STATICHOOK1();
    }

    public final boolean equals(Object object) {
        try {
            InvocationHandler invocationHandler = this.CGLIB$CALLBACK_0;
            if (invocationHandler == null) {
                BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$BIND_CALLBACKS(this);
                invocationHandler = this.CGLIB$CALLBACK_0;
            }
            return (Boolean)invocationHandler.invoke(this, CGLIB$equals$1, new Object[]{object});
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final String toString() {
        try {
            InvocationHandler invocationHandler = this.CGLIB$CALLBACK_0;
            if (invocationHandler == null) {
                BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$BIND_CALLBACKS(this);
                invocationHandler = this.CGLIB$CALLBACK_0;
            }
            return (String)invocationHandler.invoke(this, CGLIB$toString$2, new Object[0]);
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public final int hashCode() {
        try {
            InvocationHandler invocationHandler = this.CGLIB$CALLBACK_0;
            if (invocationHandler == null) {
                BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$BIND_CALLBACKS(this);
                invocationHandler = this.CGLIB$CALLBACK_0;
            }
            return ((Number)invocationHandler.invoke(this, CGLIB$hashCode$3, new Object[0])).intValue();
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    protected final Object clone() throws CloneNotSupportedException {
        try {
            InvocationHandler invocationHandler = this.CGLIB$CALLBACK_0;
            if (invocationHandler == null) {
                BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$BIND_CALLBACKS(this);
                invocationHandler = this.CGLIB$CALLBACK_0;
            }
            return invocationHandler.invoke(this, CGLIB$clone$4, new Object[0]);
        }
        catch (CloneNotSupportedException | Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public Object newInstance(Callback[] callbackArray) {
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85 bookServiceImpl$$EnhancerByCGLIB$$b0c38b85 = new BookServiceImpl$$EnhancerByCGLIB$$b0c38b85();
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$SET_THREAD_CALLBACKS(null);
        return bookServiceImpl$$EnhancerByCGLIB$$b0c38b85;
    }

    public Object newInstance(Class[] classArray, Object[] objectArray, Callback[] callbackArray) {
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85 bookServiceImpl$$EnhancerByCGLIB$$b0c38b85;
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$SET_THREAD_CALLBACKS(callbackArray);
        Class[] classArray2 = classArray;
        switch (classArray.length) {
            case 0: {
                bookServiceImpl$$EnhancerByCGLIB$$b0c38b85 = new BookServiceImpl$$EnhancerByCGLIB$$b0c38b85();
                break;
            }
            default: {
                throw new IllegalArgumentException("Constructor not found");
            }
        }
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$SET_THREAD_CALLBACKS(null);
        return bookServiceImpl$$EnhancerByCGLIB$$b0c38b85;
    }

    public Object newInstance(Callback callback) {
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$SET_THREAD_CALLBACKS(new Callback[]{callback});
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85 bookServiceImpl$$EnhancerByCGLIB$$b0c38b85 = new BookServiceImpl$$EnhancerByCGLIB$$b0c38b85();
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$SET_THREAD_CALLBACKS(null);
        return bookServiceImpl$$EnhancerByCGLIB$$b0c38b85;
    }

    public final void findAll() {
        try {
            InvocationHandler invocationHandler = this.CGLIB$CALLBACK_0;
            if (invocationHandler == null) {
                BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$BIND_CALLBACKS(this);
                invocationHandler = this.CGLIB$CALLBACK_0;
            }
            Object object = invocationHandler.invoke(this, CGLIB$findAll$0, new Object[0]);
            return;
        }
        catch (Error | RuntimeException throwable) {
            throw throwable;
        }
        catch (Throwable throwable) {
            throw new UndeclaredThrowableException(throwable);
        }
    }

    public void setCallback(int n, Callback callback) {
        switch (n) {
            case 0: {
                this.CGLIB$CALLBACK_0 = (InvocationHandler)callback;
                break;
            }
        }
    }

    public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] callbackArray) {
        CGLIB$THREAD_CALLBACKS.set(callbackArray);
    }

    public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] callbackArray) {
        CGLIB$STATIC_CALLBACKS = callbackArray;
    }

    public void setCallbacks(Callback[] callbackArray) {
        Callback[] callbackArray2 = callbackArray;
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85 bookServiceImpl$$EnhancerByCGLIB$$b0c38b85 = this;
        this.CGLIB$CALLBACK_0 = (InvocationHandler)callbackArray[0];
    }

    public Callback[] getCallbacks() {
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$BIND_CALLBACKS(this);
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85 bookServiceImpl$$EnhancerByCGLIB$$b0c38b85 = this;
        return new Callback[]{this.CGLIB$CALLBACK_0};
    }

    public Callback getCallback(int n) {
        InvocationHandler invocationHandler;
        BookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$BIND_CALLBACKS(this);
        switch (n) {
            case 0: {
                invocationHandler = this.CGLIB$CALLBACK_0;
                break;
            }
            default: {
                invocationHandler = null;
            }
        }
        return invocationHandler;
    }

    static void CGLIB$STATICHOOK1() {
        CGLIB$THREAD_CALLBACKS = new ThreadLocal();
        CGLIB$findAll$0 = Class.forName("com.briup.aop.proxy.dproxy.cglib.BookServiceImpl").getDeclaredMethod("findAll", new Class[0]);
        CGLIB$equals$1 = Class.forName("java.lang.Object").getDeclaredMethod("equals", Class.forName("java.lang.Object"));
        CGLIB$toString$2 = Class.forName("java.lang.Object").getDeclaredMethod("toString", new Class[0]);
        CGLIB$hashCode$3 = Class.forName("java.lang.Object").getDeclaredMethod("hashCode", new Class[0]);
        CGLIB$clone$4 = Class.forName("java.lang.Object").getDeclaredMethod("clone", new Class[0]);
    }

    private static final void CGLIB$BIND_CALLBACKS(Object object) {
        block2: {
            Object object2;
            block3: {
                BookServiceImpl$$EnhancerByCGLIB$$b0c38b85 bookServiceImpl$$EnhancerByCGLIB$$b0c38b85 = (BookServiceImpl$$EnhancerByCGLIB$$b0c38b85)object;
                if (bookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$BOUND) break block2;
                bookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$BOUND = true;
                object2 = CGLIB$THREAD_CALLBACKS.get();
                if (object2 != null) break block3;
                object2 = CGLIB$STATIC_CALLBACKS;
                if (CGLIB$STATIC_CALLBACKS == null) break block2;
            }
            bookServiceImpl$$EnhancerByCGLIB$$b0c38b85.CGLIB$CALLBACK_0 = (InvocationHandler)((Callback[])object2)[0];
        }
    }
}

spring集成代理

未增强前

ICategoryService

public interface ICategoryService {
	void findAll();
}

CategoryServiceImpl

public class CategoryServiceImpl implements ICategoryService{
       @Override
	public void findAll() {
		System.out.println("模拟 查询所有目录");
	}
}

bean.xml

<bean id = "categoryService" class="com.briup.aop.demo.service.impl.CategoryServiceImpl"></bean>

TestAop

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:bean.xml")
public class TestAop {
	@Autowired
	private ICategoryService categoryService;
	@Test
	public void test() {
		//categoryService.findAll();
		categoryService.insert();
	}
}

后置处理器

MyBeanPostProcessor 生命周期的一环

public class MyBeanPostProcessor implements BeanPostProcessor{
	private LogUtil logUtil;
	public void setLogUtil(LogUtil logUtil) {
		this.logUtil = logUtil;
	}
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if("categoryService".equals(beanName)) {
//			System.out.println(bean);
//			System.out.println(beanName);
			return Proxy.newProxyInstance(
					bean.getClass().getClassLoader(), 
					bean.getClass().getInterfaces(), 
					new InvocationHandler() {
						
						@Override
						public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
							System.out.println("hello");
							Object result = method.invoke(bean, args);
							System.out.println("world");
							return result;
						}
					});
		}
		return bean;
	}
}

bean.xml

 <bean id = "myPostProcessor" class="com.briup.aop.demo.life.MyBeanPostProcessor"></bean>

日志改造 LogUtil

public class LogUtil {
	public void before() {
		System.out.println("执行前");
	}
	public void after() {
		System.out.println("执行后");
	}
}
public class MyBeanPostProcessor implements BeanPostProcessor{
	private LogUtil logUtil;
	public void setLogUtil(LogUtil logUtil) {
		this.logUtil = logUtil;
	}
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if(beanName.startsWith("user")) {
//			System.out.println(bean);
//			System.out.println(beanName);
			return Proxy.newProxyInstance(
					bean.getClass().getClassLoader(), 
					bean.getClass().getInterfaces(), 
					new InvocationHandler() {
						
						@Override
						public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//							System.out.println("hello");
							logUtil.before();
							Object result = method.invoke(bean, args);
							logUtil.after();
//							System.out.println("world");
							return result;
						}
					});
		}
		return bean;
	}
}

bean.xml

<bean id = "logUtil" class="com.briup.aop.demo.aspect.LogUtil"/>
<bean id = "myPostProcessor" class="com.briup.aop.demo.life.MyBeanPostProcessor">
		<property name="logUtil" ref="logUtil"/>
	</bean>

aop

此处需要导入aspectjweaver-1.9.4.jar

AOP就是面向切面编程,是一种非常适合在无须修改业务代码的前提下,对某个或某些业务增加同一的功能,比如日志记录,权限控制,事务管理等,能很好的使得代码解耦,提高开发效率。

  • advice 通知,建议。
    • 在Spring中通过定义Advice来定义代理逻辑
  • pointcut 切入点
    • 表示Advice对应的代理逻辑应用在哪个类,哪个方法上
  • advisor advice + pontcut
    • 表示代理逻辑和切点的一个整体,可通过定义或封装一个Advisor,来定义切点和代理逻辑
  • weaving 织入
    • 将Advice代理逻辑在源代码级别嵌入到切点的过程,叫做织入
  • target 目标对象
    • 被代理对象,在aop生成的代理对象中会持有目标对象
  • join point 连接点
    • 在Spring Aop中就是方法的执行点

AOP的工作原理

AOP是发生在Bean的生命周期过程中

  • Spring生成Bean对象时,先实例化出来一个对象,也就是target对象
  • 再对target对象进行属性填充
  • 再初始化后步骤中,会判断target对象有没有对应的切面
  • 如果有切面,就表示当前target对象需要进行AOP
  • 通过Cglib或JDK动态代理机制生成一个代理对象,作为最终的bean对象

bean.xml

 <aop:config>
	<aop:pointcut expression="execution(* com.briup.aop.demo.service..*.*(..))" id="myPoint"/>
	<aop:aspect ref="logUtil">
		<aop:before method="before" pointcut-ref="myPoint"/>
		<aop:after method="after" pointcut-ref="myPoint"/>
	</aop:aspect>
</aop:config>

事务

导入jar

  • spring-tx-5.0.2.RELEASE.jar
  • spring-jdbc-5.0.2.RELEASE.jar
  • druid-1.1.10.jar
  • mysql-connector-java-5.1.7-bin.jar

编程式事务

使用编程的方式,自己去实现事务管理工作,例如事务的开启、提交、回滚操作,需要开发人员自己调用commit()或者rollback()等方法来实现。 编程式事务需要我们自己在逻辑代码中手动书写事务控制逻辑,所以编程式事务是具有侵入性的。 我们之前的代码中,对事务进行提交或者回滚的操作,就属于编程式事务。

CategoryDaoImpl

public class CategoryDaoImpl implements CategoryDao{
	private JdbcTemplate JdbcTemplate;
	
	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		JdbcTemplate = jdbcTemplate;
	}

	@Override
	public void insert() {
		String sql = "insert into es_category(name,description) values('vanse','hello')";
		JdbcTemplate.update(sql);
	}

}

CategoryServiceImpl

public class CategoryServiceImpl implements ICategoryService{
	private CategoryDao categoryDao;
	private PlatformTransactionManager transactionManager;

	@Override
	public void findAll() {
		System.out.println("模拟 查询所有目录");
	}

	@Override
	public void insert() {
		TransactionDefinition definition = new DefaultTransactionDefinition();;
		TransactionStatus status = transactionManager.getTransaction(definition);
		try {
			System.out.println("模拟 插入數據");
			categoryDao.insert();
			int i = 1/0;
			transactionManager.commit(status);
		} catch (TransactionException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			transactionManager.rollback(status);
		} 
	}

	public void setCategoryDao(CategoryDao categoryDao) {
		this.categoryDao = categoryDao;
	}

	public void setTransactionManager(PlatformTransactionManager transactionManager) {
		this.transactionManager = transactionManager;
	}
	
}

bean.xml

 <bean id = "dataSource" class="com.alibaba.druid.pool.DruidDataSource">
     	<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
     	<property name="url" value="jdbc:mysql:///estore-nongda2018"></property>
     	<property name="username" value="root"></property>
     	<property name="password" value="root"></property>
       </bean>
<bean id = "jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
<bean id="categoryDao" class="com.briup.aop.demo.dao.CategoryDaoImpl">
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
<bean id = "transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>

<bean id = "categoryService" class="com.briup.aop.demo.service.impl.CategoryServiceImpl">
		<property name="categoryDao" ref="categoryDao"></property>
		<property name="transactionManager" ref="transactionManager"></property>
	</bean>

声明式事务

只需要声明或者配置一个事务就可以了,不需要我们手动去编写事务管理代码。 这种方式属于非侵入性的,可以使用AOP思想实现事务管理,能够提高代码的复用性,提高开发效率。

在Spring中,使用AOP来实现事务操作

  • 将service层事务的开启、提交、回滚等代码抽出来,封装成切面类
  • 使用环绕通知,将事务管理的代码织入到service层需要事务支持的方法中
  • 获取service 实现类的代理对象,调用方法时会动态加入事务管理的代码
<!-- aop声明式事务  
		执行commit 逻辑 回滚rollbalck (环绕通知) -->
<!-- 事务用advisor -->
<!-- 配置事务 拦截器 -->
<tx:advice transaction-manager="transactionManger" id="txAdvice">
<!-- TransactionDefiniton -->
	<tx:attributes>
		<tx:method name="insert*" rollback-for="Excetion" propagation="REQUIRED"/>
	</tx:attributes>
</tx:advice>
<aop:config>
	<!-- 增强(事务)     目标类 -->
	<aop:pointcut expression="execution(* com.briup.springaop.servcie..*.*(..))" id="cut"/>
	<!-- adviosor和adivce和aspect -->
		<!-- adviosor == advice+pointcut -->
	<aop:advisor advice-ref="txAdvice" pointcut-ref="cut"/>
</aop:config>	

总配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xmlns:tx="http://www.springframework.org/schema/tx"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd
         http://www.springframework.org/schema/tx
        https://www.springframework.org/schema/tx/spring-tx.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">

	<!-- <bean id="categoryService"
		class="com.briup.springaop.CategoryServiceImpl"></bean>
		
		自定义后置处理器
	<bean id="myPostProcessor"
		class="com.briup.springaop.MyPostProcessor">
		<property name="logUtil" ref="logUtil"></property>
		</bean>

	<bean id = "logUtil" class = "com.briup.springaop.LogUtil"></bean> -->
	
	<!-- 底层做了动态代理  后置处理器检测到该类使用的代理 -->
	
	<!-- dom4j解析 xml  aop: -->
	<!-- <aop:config>
		增强逻辑   目标类
		切入点 目标类  一串
		<aop:pointcut expression="execution(* com.briup.springaop..*.*(..))" id="myPoint"/>
		增强逻辑 
			切面类
		<aop:aspect ref="logUtil">
			<aop:before method="before" pointcut-ref="myPoint"/>
			<aop:after method="after" pointcut-ref="myPoint"/>
			拦截器   around  环绕通知  需要aop联盟的包
			<aop:around method="around" pointcut-ref="myPoint"/>
		</aop:aspect>
	</aop:config> -->
	
	
	<!-- service -->
	<bean id = "categoryService" class="com.briup.springaop.servcie.CategoryServiceImpl">
		<property name="categoryDao" ref="categoryDao"></property>
		<!-- <property name="transactionManger" ref="transactionManger"></property> -->
	</bean>
	<bean id= "transactionManger" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- dao -->
	<bean id = "categoryDao" class="com.briup.springaop.dao.CategoryDaoImpl" >
		<property name="jdbcTemplate" ref="jdbcTemplate"></property>
	</bean>
	<!-- jdbcTemplate -->
	<bean id = "jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" >
		<property name="dataSource" ref="dataSource"></property>
	</bean>
	<!-- dataSource -->
	<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
		<property name="url" value="jdbc:mysql:///estore-nongda2018"></property>
		<property name="username" value="root"></property>
		<property name="password" value="root"></property>
	</bean>
	
	
	
<!-- aop声明式事务  
		执行commit 逻辑 回滚rollbalck (环绕通知) -->
<!-- 事务用advisor -->
<!-- 配置事务 拦截器 -->
<tx:advice transaction-manager="transactionManger" id="txAdvice">
<!-- TransactionDefiniton -->
	<tx:attributes>
		<tx:method name="insert*" rollback-for="Excetion" propagation="REQUIRED"/>
	</tx:attributes>
</tx:advice>
<aop:config>
	<!-- 增强(事务)     目标类 -->
	<aop:pointcut expression="execution(* com.briup.springaop.servcie..*.*(..))" id="cut"/>
	<!-- adviosor和adivce和aspect -->
		<!-- adviosor == advice+pointcut -->
	<aop:advisor advice-ref="txAdvice" pointcut-ref="cut"/>
</aop:config>	
	
</beans>