zoukankan      html  css  js  c++  java
  • Proxy 和aop

    Proxy 就是代理,意思就是 你不用去做,别人代替你去处理

    先来个静态代理

    public interface Hello {
    
        void say(String name);
    }
    
    被代理类
    public class HelloImpl implements Hello {
    
        @Override
        public void say(String name) {
            System.out.println("Hello! " + name);
        }
    }
    
    代理类
    public class HelloProxy implements Hello {
    
        private HelloImpl helloImpl;
    
        public HelloProxy() {
            helloImpl = new HelloImpl();
        }
    
        @Override
        public void say(String name) {
            before();
            helloImpl.say(name);
            after();
        }
    
        private void before() {
            System.out.println("Before");
        }
    
        private void after() {
            System.out.println("After");
        }
    }
    静态代理

    再来个动态代理

    public class DynamicProxy implements InvocationHandler {
    
        private Object target;
    
        public DynamicProxy(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            before();
            Object result = method.invoke(target, args);
            after();
            return result;
        }
    
        @SuppressWarnings("unchecked")
        public <T> T getProxy() {
            return (T) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                this
            );
        }
    }
    
    
    public static void main(String[] args) {
        DynamicProxy dynamicProxy = new DynamicProxy(new HelloImpl());
        Hello helloProxy = dynamicProxy.getProxy();
    
        helloProxy.say("Jack");
    }
    动态代理

    但是 只能代理有借口的类

    使用 CGLib  来进行代理

    public class CGLibProxy implements MethodInterceptor {
        
       private static CGLibProxy instance = new CGLibProxy();
        
        private CGLibProxy() {
        }
    
        public static CGLibProxy getInstance() {
            return instance;
        }
    
        public <T> T getProxy(Class<T> cls) {
            return (T) Enhancer.create(cls, this);
        }
    
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            before();
            Object result = proxy.invokeSuper(obj, args);
            after();
            return result;
        }
    
        ...
    }
    
    
    public class Client {
    
        public static void main(String[] args) {
            Greeting greeting = CGLibDynamicProxy.getInstance().getProxy(GreetingImpl.class);
            greeting.sayHello("Jack");
        }
    }
    CgLib代理

    Proxy 感觉好像 Decorator 啊

    代理模式(Proxy 模式)可理解为:我想做,但不能做,我需要有一个能干的人来帮我做。        需要一个能人

    装饰器模式(Decorator 模式)可理解为:我想做,但不能做,我需要有各类特长的人来帮我做,但我有时只需要一个人,有时又需要很多人   需要一个团队

    public interface Greeting {
    
        void sayHello(String name);
    }
    
    public class GreetingImpl implements Greeting {
    
        @Override
        public void sayHello(String name) {
            System.out.println("Hello! " + name);
        }
    }
    
    public class GreetingProxy implements Greeting {
    
        private GreetingImpl greetingImpl;
    
        public GreetingProxy(GreetingImpl greetingImpl) {
            this.greetingImpl = greetingImpl;
        }
    
        @Override
        public void sayHello(String name) {
            before();
            greetingImpl.sayHello(name);
        }
    
        private void before() {
            System.out.println("Before");
        }
    }
    //开闭原则”对扩展开放,对修改封闭”。没错,我们确实是提供了 GreetingProxy 类来扩展 GreetingImpl 的功能,而并非去修改 GreetingImpl 原有的代码。
    代理模式

    如果需要做的操作越来越多,一下子是日志记录,一下子是事务控制,还有权限控制,还有数据缓存。把所有的功能都放在这个 Proxy 类中是不明智的,同时这也违反了“开闭原则”

    来看看装饰器模式

    //干净的装饰器
    public abstract class GreetingDecorator implements 接口类{
    
        private Greeting greeting;
    
        public GreetingDecorator(Greeting greeting) {
            this.greeting = greeting;
        }
    
        @Override
        public void sayHello(String name) {
            greeting.sayHello(name);
        }
    }
    
    //日志功能
    public class GreetingBefore extends GreetingDecorator {
    
        public GreetingBefore(Greeting greeting) {
            super(greeting);
        }
    
        @Override
        public void sayHello(String name) {
            before();
            super.sayHello(name);
        }
    
        private void before() {
            System.out.println("Before");
        }
    }
    
    //其他功能
    public class GreetingAfter extends GreetingDecorator {
    
        public GreetingAfter(Greeting greeting) {
            super(greeting);
        }
    
        @Override
        public void sayHello(String name) {
            super.sayHello(name);
            after();
        }
    
        private void after() {
            System.out.println("After");
        }
    }
    
    //使用
    public class ClientDecorator {
    
        public static void main(String[] args) {
            Greeting greeting = new GreetingAfter(new GreetingBefore(new GreetingImpl()));
            greeting.sayHello("Jack");
        }
    }
    装饰器模式
    这就使用了装饰器模式
    InputStream input = new DataInputStream(new BufferedInputStream(new FileInputStream("C:/test.exe")));

    Spring AOP:前置增强、后置增强、环绕增强  抛出增强(ThrowsAdvice )

    前,后置增强
    public class GreetingBeforeAndAfterAdvice implements MethodBeforeAdvice, AfterReturningAdvice {
    
        @Override
        public void before(Method method, Object[] args, Object target) throws Throwable {
            System.out.println("Before");
        }
    
        @Override
        public void afterReturning(Object result, Method method, Object[] args, Object target) throws Throwable {
            System.out.println("After");
        }
    }
    
    public class Client {
    
        public static void main(String[] args) {
            ProxyFactory proxyFactory = new ProxyFactory();     // 创建代理工厂
            proxyFactory.setTarget(new GreetingImpl());         // 射入目标类对象
            proxyFactory.addAdvice(new GreetingBeforeAdvice()); // 添加前置增强
            proxyFactory.addAdvice(new GreetingAfterAdvice());  // 添加后置增强 
    
            Greeting greeting = (Greeting) proxyFactory.getProxy(); // 从代理工厂中获取代理
            greeting.sayHello("Jack");                              // 调用代理的方法
        }
    }
    
    也可以实现MethodInterceptor   实现环绕增强
    编程式增强
        <!-- 扫描指定包(将 @Component 注解的类自动定义为 Spring Bean) -->
        <context:component-scan base-package="aop.demo"/>
    
        <!-- 配置一个代理 -->
        <bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="interfaces" value="aop.Greeting"/> <!-- 需要代理的接口 -->
            <property name="target" ref="greetingImpl"/>       <!-- 接口实现类 -->
            <property name="interceptorNames">                 <!-- 拦截器名称(也就是增强类名称,Spring Bean 的 id) -->
                <list>
                    <value>greetingAroundAdvice</value>
                </list>
            </property>
        </bean>
    
    </beans>
    
    加上@Component
    
    public class Client {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("aop/demo/spring.xml"); // 获取 Spring Context
            Greeting greeting = (Greeting) context.getBean("greetingProxy");                        // 从 Context 中根据 id 获取 Bean 对象(其实就是一个代理)
            greeting.sayHello("Jack");                                                              // 调用代理的方法
        }
    }
    xml声明式

    引入增强(如果某个类实现了 A 接口,但没有实现 B 接口,那么该类可以调用 B 接口的方法吗?)

    新定义B接口
    public interface Apology {
        void saySorry(String name);
    }
    
    @Component
    public class GreetingIntroAdvice extends DelegatingIntroductionInterceptor implements Apology {
    
        @Override
        public Object invoke(MethodInvocation invocation) throws Throwable {
            return super.invoke(invocation);
        }
    
        @Override
        public void saySorry(String name) {
            System.out.println("Sorry! " + name);
        }
    }
    
        <bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="interfaces" value="aop.demo.Apology"/>          <!-- 需要动态实现的接口 -->
            <property name="target" ref="greetingImpl"/>                    <!-- 目标类 -->
            <property name="interceptorNames" value="greetingIntroAdvice"/> <!-- 引入增强 -->
            <property name="proxyTargetClass" value="true"/>                <!-- 代理目标类(默认为 false,代理接口) -->
        </bean>
    
    
    public class Client {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("aop/demo/spring.xml");
            GreetingImpl greetingImpl = (GreetingImpl) context.getBean("greetingProxy"); // 注意:转型为目标类,而并非它的 Greeting 接口
            greetingImpl.sayHello("Jack");
    
            Apology apology = (Apology) greetingImpl; // 将目标类强制向上转型为 Apology 接口(这是引入增强给我们带来的特性,也就是“接口动态实现”功能)
            apology.saySorry("Jack");
        }
    }
    引入增强

    前面全是拦截整个类,有时候老子不需要拦不漂亮的,与是就想到了spring 的切面(Advisor)

    将拦截匹配条件(Pointcut)与增强(Advice)结合在一起

    @Component
    public class GreetingImpl implements Greeting {
    
        @Override
        public void sayHello(String name) {
            System.out.println("Hello! " + name);
        }
    
        public void goodMorning(String name) {
            System.out.println("Good Morning! " + name);
        }
    
        public void goodNight(String name) {
            System.out.println("Good Night! " + name);
        }
    }
    
    
    <beans ...">
    
        <context:component-scan base-package="aop.demo"/>
    
        <!-- 配置一个切面 -->
        <bean id="greetingAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
            <property name="advice" ref="greetingAroundAdvice"/>            <!-- 增强 -->
            <property name="pattern" value="aop.demo.GreetingImpl.good.*"/> <!-- 切点(正则表达式) -->匹配 aop.demo.GreetingImpl 类中以 good 开头的方法”
        </bean>
    
        <!-- 配置一个代理 -->
        <bean id="greetingProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
            <property name="target" ref="greetingImpl"/>                <!-- 目标类 -->
            <property name="interceptorNames" value="greetingAdvisor"/> <!-- 切面 -->
            <property name="proxyTargetClass" value="true"/>            <!-- 代理目标类 -->
        </bean>
    
    </beans>
    
    DefaultPointcutAdvisor:默认切面(可扩展它来自定义切面)
    
    NameMatchMethodPointcutAdvisor:根据方法名称进行匹配的切面
    
    StaticMethodMatcherPointcutAdvisor:用于匹配静态方法的切面
    切面来配置代理

    让用户去配置一个或少数几个代理,似乎还可以接受,但随着项目的扩大,代理配置就会越来越多,配置的重复劳动就多了,麻烦不说,还很容易出错。能否让 Spring 框架为我们自动生成代理

      <bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
            <property name="beanNames" value="*Impl"/>                       <!-- 只为后缀是“Impl”的 Bean 生成代理 -->
            <property name="interceptorNames" value="greetingAroundAdvice"/> <!-- 增强 -->
            <property name="optimize" value="true"/>                         <!-- 是否对代理生成策略进行优化 -->
        </bean>
    
    以上使用 BeanNameAutoProxyCreator 只为后缀为“Impl”的 Bean 生成代理。需要注意的是,这个地方我们不能定义代理接口,也就是 interfaces 属性,因为我们根本就不知道这些 Bean 到底实现了多少接口。此时不能代理接口,而只能代理类。所以这里提供了一个新的配置项,它就是 optimize。若为 true 时,则可对代理生成策略进行优化(默认是 false 的)。也就是说,如果该类有接口,就代理接口(使用 JDK 动态代理);如果没有接口,就代理类(使用 CGLib 动态代理)。而并非像之前使用的 proxyTargetClass 属性那样,强制代理类,而不考虑代理接口的方式
    
    既然 CGLib 可以代理任何的类了,那为什么还要用 JDK 的动态代理呢?肯定您会这样问。
    
    根据多年来实际项目经验得知:CGLib 创建代理的速度比较慢,但创建代理后运行的速度却非常快,而 JDK 动态代理正好相反。如果在运行的时候不断地用 CGLib 去创建代理,系统的性能会大打折扣,所以建议一般在系统初始化的时候用 CGLib 去创建代理,并放入 Spring 的 ApplicationContext 中以备后用。
    
    以上这个例子只能匹配目标类,而不能进一步匹配其中指定的方法,要匹配方法,就要考虑使用切面与切点了。
    自动代理

    上面配置实在是累啊,想拦截指定注解的方法,我们就必须扩展 DefaultPointcutAdvisor 类,自定义一个切面类,然后在 Spring 配置文件中进行切面配置

    Spring + AspectJ

    @Aspect
    @Component
    public class GreetingAspect {
    
        @Around("execution(* aop.demo.GreetingImpl.*(..))")
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            before();
            Object result = pjp.proceed();
            after();
            return result;
        }
    
        private void before() {
            System.out.println("Before");
        }
    
        private void after() {
            System.out.println("After");
        }
    }
    execution():表示拦截方法,括号中可定义需要匹配的规则。
    
    第一个“*”:表示方法的返回值是任意的。
    
    第二个“*”:表示匹配该类中所有的方法。
    
    (..):表示方法的参数是任意的。
    
    <context:component-scan base-package="aop.demo"/>
    
        <aop:aspectj-autoproxy proxy-target-class="true"/>
      默认为false(只能代理接口),为true时,代理目标类(使用CGLib动态代理)
    基于注解:通过 AspectJ execution 表达式拦截方法

     Spring 与 AspectJ 结合的威力远远不止这些,我们来点时尚的吧,拦截指定注解的方法怎么样?

    //先定义一个注解,标注在方法上,运行时生效
    @Target(ElementType.METHOD)
    @Retention(RetentionPolicy.RUNTIME)
    public @interface Tag {
    }
    
    //只需将前面的 Aspect 类的切点表达式稍作改动:
    @Aspect
    @Component
    public class GreetingAspect {
    
        @Around("@annotation(aop.demo.Tag)")  // 拦截有这个注解的
        public Object around(ProceedingJoinPoint pjp) throws Throwable {
            ...
        }
    
        ...
    }
    
    //被拦截的,将 @Tag 注解定义在您想要拦截的方法上
    @Component
    public class GreetingImpl implements Greeting {
    
        @Tag
        @Override
        public void sayHello(String name) {
            System.out.println("Hello! " + name);
        }
    }
    
    
    @Before:前置增强
    
    @After:后置增强
    
    @Around:环绕增强
    
    @AfterThrowing:抛出增强
    
    @DeclareParents:引入增强
    基于注解:通过 AspectJ @annotation 表达式拦截方法

    实现下牛B的引入增强

    @Aspect
    @Component
    public class GreetingAspect {
    
        @DeclareParents(value = "aop.demo.GreetingImpl", defaultImpl = ApologyImpl.class)
        private Apology apology;
    }
    
    value:目标类
    
    defaultImpl:引入接口的默认实现类
    
    public class ApologyImpl implements Apology {
    
        @Override
        public void saySorry(String name) {
            System.out.println("Sorry! " + name);
        }
    }
    
    public class Client {
    
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext("aop/demo/spring.xml");
            Greeting greeting = (Greeting) context.getBean("greetingImpl");
            greeting.sayHello("Jack");
    
            Apology apology = (Apology) greeting; // 强制转型为 Apology 接口
            apology.saySorry("Jack");
        }
    }
    
    从 Spring ApplicationContext 中获取 greetingImpl 对象(其实是个代理对象),可转型为自己静态实现的接口 Greeting,也可转型为自己动态实现的接口 Apology,切换起来非常方便
    引入增强

    对于jdk1.4以下没有注解的只能通过配置来使用的

    <beans ...">
    
        <bean id="greetingImpl" class="aop.demo.GreetingImpl"/>
    
        <bean id="greetingAspect" class="aop.demo.GreetingAspect"/>
    
        <aop:config>
            <aop:aspect ref="greetingAspect">
                <aop:around method="around" pointcut="execution(* aop.demo.GreetingImpl.*(..))"/>
            </aop:aspect>
        </aop:config>
    
    </beans>
    xml切 ,一点都不好用

    spring

    AOP原理

    实现轻量级AOP

    @Bean
    @Aspect(pkg = "com.smart.sample.action", cls = "ProductAction")
    public class ProductActionAspect extends BaseAspect {
    
        @Override
        protected Object advice(Pointcut pointcut, Object proxy, Object[] args) {
            long begin = System.currentTimeMillis();
    
            Object result = pointcut.invoke(proxy, args);
    
            System.out.println("Time: " + (System.currentTimeMillis() - begin) + "ms");
    
            return result;
        }
    }
    
    
    //使用了Cglib
    public abstract class BaseAspect implements MethodInterceptor {
    
        @SuppressWarnings("unchecked")
        public <T> T getProxy(Class<T> cls) {
            return (T) Enhancer.create(cls, this);
        }
    
        @Override
        public Object intercept(Object proxy, Method methodTarget, Object[] args, MethodProxy methodProxy) throws Throwable {
            return advice(new Pointcut(methodTarget, methodProxy), proxy, args);
        }
    
        protected abstract Object advice(Pointcut pointcut, Object proxy, Object[] args);
    
        protected class Pointcut {
    
            private Method methodTarget;
            private MethodProxy methodProxy;
    
            public Pointcut(Method methodTarget, MethodProxy methodProxy) {
                this.methodTarget = methodTarget;
                this.methodProxy = methodProxy;
            }
    
            public Method getMethodTarget() {
                return methodTarget;
            }
    
            public MethodProxy getMethodProxy() {
                return methodProxy;
            }
    
            public Object invoke(Object proxy, Object[] args) {
                Object result = null;
                try {
                    result = methodProxy.invokeSuper(proxy, args);
                } catch (Throwable e) {
                    e.printStackTrace();
                }
                return result;
            }
        }
    }
    v1.1AOP
    public class AOPHelper {
    
        static {
            try {
                // 获取带有 @Aspect 注解的类(切面类)
                List<Class<?>> aspectClassList = ClassHelper.getClassListByAnnotation(Aspect.class);
                // 遍历所有切面类
                for (Class<?> aspectClass : aspectClassList) {
                    // 获取 @Aspect 注解中的属性值
                    Aspect aspect = aspectClass.getAnnotation(Aspect.class);
                    String pkg = aspect.pkg(); // 包名
                    String cls = aspect.cls(); // 类名
                    // 初始化目标类列表
                    List<Class<?>> targetClassList = new ArrayList<Class<?>>();
                    if (StringUtil.isNotEmpty(pkg) && StringUtil.isNotEmpty(cls)) {
                        // 如果包名与类名均不为空,则添加指定类
                        targetClassList.add(Class.forName(pkg + "." + cls));
                    } else {
                        // 否则(包名不为空)添加该包名下所有类
                        targetClassList.addAll(ClassHelper.getClassListByPackage(pkg));
                    }
                    // 遍历目标类列表
                    if (CollectionUtil.isNotEmpty(targetClassList)) {
                        // 创建父切面类
                        BaseAspect baseAspect = (BaseAspect) aspectClass.newInstance();
                        for (Class<?> targetClass : targetClassList) {
                            // 获取目标实例
                            Object targetInstance = BeanHelper.getBean(targetClass);
                            // 创建代理实例
                            Object proxyInstance = baseAspect.getProxy(targetClass);
                            // 复制目标实例中的字段到代理实例中
                            for (Field field : targetClass.getDeclaredFields()) {
                                field.setAccessible(true); // 可操作私有字段
                                field.set(proxyInstance, field.get(targetInstance));
                            }
                            // 用代理实例覆盖目标实例
                            BeanHelper.getBeanMap().put(targetClass, proxyInstance);
                        }
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
    处理注解类

    想要拦截特定方法

    @Override
    protected Object advice(Pointcut pointcut, Object proxy, Object[] args) {
        Object result;
        Method method = pointcut.getMethodTarget();
        if (method.getName().equals("getProducts")) {
            long begin = System.currentTimeMillis();
            result = pointcut.invoke(proxy, args);
            System.out.println("Time: " + (System.currentTimeMillis() - begin) + "ms");
        } else {
            result = pointcut.invoke(proxy, args);
        }
        return result;
    }
    拦截特定方法进行处理
    //去掉pointcut
    public abstract class BaseAspect implements MethodInterceptor {
    
        @SuppressWarnings("unchecked")
        public <T> T getProxy(Class<T> cls) {
            return (T) Enhancer.create(cls, this);
        }
    
        @Override
        public Object intercept(Object proxy, Method methodTarget, Object[] args, MethodProxy methodProxy) throws Throwable {
            Object result = null;
            if (filter(methodTarget, args)) {
                before(methodTarget, args);
                try {
                    result = methodProxy.invokeSuper(proxy, args);
                } catch (Exception e) {
                    e.printStackTrace();
                    error(methodTarget, args, e);
                }
                after(methodTarget, args);
            } else {
                result = methodProxy.invokeSuper(proxy, args);
            }
            return result;
        }
    
        protected boolean filter(Method method, Object[] args) {
            return true;
        }
    
        protected void before(Method method, Object[] args) {
        }
    
        protected void after(Method method, Object[] args) {
        }
    
        protected void error(Method method, Object[] args, Exception e) {
        }
    }
    
    @Bean
    @Aspect(pkg = "com.smart.sample.action", cls = "ProductAction")
    public class ProductActionAspect extends BaseAspect {
    
        private long begin;
    
        @Override
        protected boolean filter(Method method, Object[] args) {
            return method.getName().equals("getProducts");
        }
    
        @Override
        protected void before(Method method, Object[] args) {
            begin = System.currentTimeMillis();
        }
    
        @Override
        protected void after(Method method, Object[] args) {
            System.out.println("Time: " + (System.currentTimeMillis() - begin) + "ms");
        }
    
        @Override
        protected void error(Method method, Object[] args, Exception e) {
            System.out.println("Error: " + e.getMessage());
        }
    }
    最终版本

    事务管理实现原理 (事务隔离级别、事务传播行为、事务超时等搞不动)

    @Bean
    public class ProductServiceImpl extends BaseService implements ProductService {
    
        ...
    
        @Override
        @Transaction
        public boolean createProduct(Map<String, Object> productFieldMap) {
            String sql = SQLHelper.getSQL("insert.product");
            Object[] params = {
                productFieldMap.get("productTypeId"),
                productFieldMap.get("productName"),
                productFieldMap.get("productCode"),
                productFieldMap.get("price"),
                productFieldMap.get("description")
            };
            int rows = DBHelper.update(sql, params);
            if (true) {
                throw new RuntimeException("Insert log failure!"); // 故意抛出异常,让事务回滚
            }
            return rows == 1;
        }
    }
    
    
    public class DBHelper {
    
        private static final BasicDataSource ds = new BasicDataSource();
        private static final QueryRunner runner = new QueryRunner(ds);
    
        // 定义一个局部线程变量(使每个线程都拥有自己的连接)
        private static ThreadLocal<Connection> connContainer = new ThreadLocal<Connection>();
    
        static {
            System.out.println("Init DBHelper...");
    
            // 初始化数据源
            ds.setDriverClassName(ConfigHelper.getStringProperty("jdbc.driver"));
            ds.setUrl(ConfigHelper.getStringProperty("jdbc.url"));
            ds.setUsername(ConfigHelper.getStringProperty("jdbc.username"));
            ds.setPassword(ConfigHelper.getStringProperty("jdbc.password"));
            ds.setMaxActive(ConfigHelper.getNumberProperty("jdbc.max.active"));
            ds.setMaxIdle(ConfigHelper.getNumberProperty("jdbc.max.idle"));
        }
    
        // 获取数据源
        public static DataSource getDataSource() {
            return ds;
        }
    
        // 开启事务
        public static void beginTransaction() {
            Connection conn = connContainer.get();
            if (conn == null) {
                try {
                    conn = ds.getConnection();
                    conn.setAutoCommit(false);
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    connContainer.set(conn);
                }
            }
        }
    
        // 提交事务
        public static void commitTransaction() {
            Connection conn = connContainer.get();
            if (conn != null) {
                try {
                    conn.commit();
                    conn.close();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    connContainer.remove();
                }
            }
        }
    
        // 回滚事务
        public static void rollbackTransaction() {
            Connection conn = connContainer.get();
            if (conn != null) {
                try {
                    conn.rollback();
                    conn.close();
                } catch (Exception e) {
                    e.printStackTrace();
                } finally {
                    connContainer.remove();
                }
            }
        }
    
        ...
    
        // 执行更新(包括 UPDATE、INSERT、DELETE)
        public static int update(String sql, Object... params) {
            // 若当前线程中存在连接,则传入(用于事务处理),否则将从数据源中获取连接
            Connection conn = connContainer.get();
            return DBUtil.update(runner, conn, sql, params);
        }
    }
    
    
    public class DBUtil {
    
        ...
    
        // 更新(包括 UPDATE、INSERT、DELETE,返回受影响的行数)
        public static int update(QueryRunner runner, Connection conn, String sql, Object... params) {
            int result = 0;
            try {
    //对传进来的conn进行判断。为空,就DataSource 中自动获取,无需考虑事务问题,是自动提交的
    //若不为空,就是处理过的conn,设置不自动提交,包含事务
                if (conn != null) {
                    result = runner.update(conn, sql, params);
                } else {
                    result = runner.update(sql, params);
                }
            } catch (SQLException e) {
                e.printStackTrace();
            }
            return result;
        }
    }
    
    //通过动态代理实现事务的开启与关闭
    public class TransactionProxy implements MethodInterceptor {
    
        private static TransactionProxy instance = new TransactionProxy();
    
        private TransactionProxy() {
        }
    
        public static TransactionProxy getInstance() {
            return instance;
        }
    
        @SuppressWarnings("unchecked")
        public <T> T getProxy(Class<T> cls) {
            return (T) Enhancer.create(cls, this);
        }
    
        @Override
        public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
            Object result;
            if (method.isAnnotationPresent(Transaction.class)) {
                try {
                    // 开启事务
                    DBHelper.beginTransaction();
    
                    // 执行操作
                    method.setAccessible(true);
                    result = proxy.invokeSuper(obj, args);
    
                    // 提交事务
                    DBHelper.commitTransaction();
                } catch (Exception e) {
                    // 回滚事务
                    DBHelper.rollbackTransaction();
    
                    e.printStackTrace();
                    throw new RuntimeException();
                }
            } else {
                result = proxy.invokeSuper(obj, args);
            }
            return result;
        }
    }
    
    
    
    负责IOC的容器
    public class BeanHelper {
    
        // Bean 类 => Bean 实例
        private static final Map<Class<?>, Object> beanMap = new HashMap<Class<?>, Object>();
    
        static {
            System.out.println("Init BeanHelper...");
    
            try {
                // 获取并遍历所有的 Bean(带有 @Bean 注解的类)
                List<Class<?>> beanClassList = ClassHelper.getClassListByAnnotation(Bean.class);
                for (Class<?> beanClass : beanClassList) {
                    // 创建 Bean 实例
                    Object beanInstance;
                    if (BaseService.class.isAssignableFrom(beanClass)) {
                        // 若为 Service 类,则获取动态代理实例(可以使用 CGLib 动态代理,不能使用 JDK 动态代理,因为初始化 Bean 字段时会报错)
                        beanInstance = TransactionProxy.getInstance().getProxy(beanClass);
                    } else {
                        // 否则通过反射创建实例
                        beanInstance = beanClass.newInstance();
                    }
                    // 将 Bean 实例放入 Bean Map 中(键为 Bean 类,值为 Bean 实例)
                    beanMap.put(beanClass, beanInstance);
                }
    
                // 遍历 Bean Map
                for (Map.Entry<Class<?>, Object> beanEntry : beanMap.entrySet()) {
                    ...
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    
        ...
    }
    事务实现原理

    当我CgLib  不能嵌套增强 , 像 装饰器那种那样 

    于是想到了借鉴 Servlet 的 Filter Chain 的设计模式,它是“责任链模式”的一种变体,在 JavaEE 设计模式中命名为“拦截过滤器模式”

    public interface Proxy {
    
        void doProxy(ProxyChain proxyChain);
    }
    
    public class ProxyChain {
    
        private List<Proxy> proxyList;
        private int currentProxyIndex = 0;
    
        private Class<?> targetClass;
        private Object targetObject;
        private Method targetMethod;
        private Object[] methodParams;
        private MethodProxy methodProxy;
        private Object methodResult;
    
        public ProxyChain(Class<?> targetClass, Object targetObject, Method targetMethod, Object[] methodParams, MethodProxy methodProxy, List<Proxy> proxyList) {
            this.targetClass = targetClass;
            this.targetObject = targetObject;
            this.targetMethod = targetMethod;
            this.methodParams = methodParams;
            this.methodProxy = methodProxy;
            this.proxyList = proxyList;
        }
    
        public Class<?> getTargetClass() {
            return targetClass;
        }
    
        public Object getTargetObject() {
            return targetObject;
        }
    
        public Method getTargetMethod() {
            return targetMethod;
        }
    
        public Object[] getMethodParams() {
            return methodParams;
        }
    
        public MethodProxy getMethodProxy() {
            return methodProxy;
        }
    
        public Object getMethodResult() {
            return methodResult;
        }
    
        public void doProxyChain() {
            if (currentProxyIndex < proxyList.size()) {
                proxyList.get(currentProxyIndex++).doProxy(this);
            } else {
                try {
                    methodResult = methodProxy.invokeSuper(targetObject, methodParams);
                } catch (Throwable throwable) {
                    throw new RuntimeException(throwable);
                }
            }
        }
    }
    
    public class ProxyManager {
    
        private Class<?> targetClass;
        private List<Proxy> proxyList;
    
        public ProxyManager(Class<?> targetClass, List<Proxy> proxyList) {
            this.targetClass = targetClass;
            this.proxyList = proxyList;
        }
    
        private static ProxyManager instance = null;
    
        private ProxyManager() {
        }
    
        public static ProxyManager getInstance() {
            if (instance == null) {
                instance = new ProxyManager();
            }
            return instance;
        }
    
        @SuppressWarnings("unchecked")
        public <T> T createProxy() {
            return (T) Enhancer.create(targetClass, new MethodInterceptor() {
                @Override
                public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
                    ProxyChain proxyChain = new ProxyChain(targetClass, target, method, args, proxy, proxyList);
                    proxyChain.doProxyChain();
                    return proxyChain.getMethodResult();
                }
            });
        }
    }
    
    
    //我们的目标不是为了实现 Proxy,而是为了实现 AOP。为了实现 AOP,我采用了“模板方法模式”,
    弄一个 AbstractProxy 抽象类,让它去实现 Proxy 接口,并在其中定义方法调用模板,在需要横向拦截的地方,定义一些“钩子方法”
    public abstract class AbstractProxy implements Proxy {
    
        @Override
        public final void doProxy(ProxyChain proxyChain) {
            Class<?> cls = proxyChain.getTargetClass();
            Method method = proxyChain.getTargetMethod();
            Object[] params = proxyChain.getMethodParams();
    
            begin();
            try {
                if (filter(cls, method, params)) {
                    before(cls, method, params);
                    proxyChain.doProxyChain();
                    after(cls, method, params);
                } else {
                    proxyChain.doProxyChain();
                }
            } catch (Throwable e) {
                error(cls, method, params, e);
            } finally {
                end();
            }
        }
    
        public void begin() {
        }
    
        public boolean filter(Class<?> cls, Method method, Object[] params) {
            return true;
        }
    
        public void before(Class<?> cls, Method method, Object[] params) {
        }
    
        public void after(Class<?> cls, Method method, Object[] params) {
        }
    
        public void error(Class<?> cls, Method method, Object[] params, Throwable e) {
        }
    
        public void end() {
        }
    }
    
    利用 AbstractProxy 重新实现 BeforeProxy 与 AfterProxy
    
    public class BeforeProxy extends AbstractProxy {
    
        @Override
        public void before(Class<?> cls, Method method, Object[] params) {
            System.out.println("Before");
        }
    }
    
    public class AfterProxy extends AbstractProxy {
    
        @Override
        public void after(Class<?> cls, Method method, Object[] params) {
            System.out.println("After");
        }
    }
    
    //Client 类
    //先构造一个空的 List<Proxy> proxyList,然后往里面依次放入需要增强的 Proxy 类,
    //随后使用 ProxyManager 去创建代理实例,最后调用代理实例的方法,完成对目标方法的横切
    public class Client {
    
        public static void main(String[] args) {
            List<Proxy> proxyList = new ArrayList<Proxy>();
            proxyList.add(new BeforeProxy());
            proxyList.add(new AfterProxy());
    
            ProxyManager proxyManager = new ProxyManager(GreetingImpl.class, proxyList);
            GreetingImpl greetingProxy = proxyManager.createProxy();
    
            greetingProxy.sayHello("Jack");
        }
    }
    链式代理

    在springboot中的运用   在加入Spring-data-jpa 发现已被引入了

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-aop</artifactId>
    </dependency>

    可以加上这个注解@EnableAspectJAutoProxy

    @Aspect
    @Component

    曾经觉得AOP这个概念很神奇,认真研究过之后发现现实实现总有很多限制,越来越觉得这个不就是管道事件的另一个说法吗?区别就是事件得预先定义,AOP可以后续注入,但总觉得后续注入这个需求是程序员自己偷懒的做法,不是业务模型架构该有的设计,不值得提倡,业务场景中应用Aop 无外乎 : 方法级权限、方法结果缓存、数据库事务、日志记录、性能统计

  • 相关阅读:
    vue 实现表格导出Excel
    基于canvas绘制的,Vue 图形验证码组件
    screenfull.js实现全屏功能
    学习笔记-Python基础2-表达式和运算符
    PHP里对数据库增删改查操作
    学习笔记-Python基础1-变量命名和声明、数据类型
    PHP类中的$this、self、parent关键字使用总结
    移动端页面中,有时需要禁止用户滑动屏幕
    正则表达式总结
    input输入框限制各类输入总结
  • 原文地址:https://www.cnblogs.com/mxz1994/p/8205870.html
Copyright © 2011-2022 走看看