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 无外乎 : 方法级权限、方法结果缓存、数据库事务、日志记录、性能统计

posted @ 2018-01-05 17:33  jojoworld  阅读(305)  评论(0编辑  收藏  举报