spring概述(四)--代理及AOP简介、配置

spring 个人记录

增强功能

事务开启,提交和回滚代码

public class TransactionManager {
    public void begin(){
        System.out.println("开启一个事务");
    }

    public void commit(){
        System.out.println("提交一个事务");
    }

    public void rollback(){
        System.out.println("回滚一个事务");
    }
}
public class EmployeeServiceImpl implements IEmployeeService {
    @Override
    public void save() {
        System.out.println(1/0);
        System.out.println("保存一个员工");
    }
    
    @Override
    public void update() {
        System.out.println("更新一个员工");
    }
}

装饰设计模式

装饰设计模式:在不必改变源代码基础上,动态地扩展一个对象的功能。
它是通过创建一个包装对象,也就是包裹真实的对象。
说的直白点,就是对已有对象进行功能增强!
1.装饰模式思想
2.装饰模式实现

得定义一个类(EmployeeService的包装类):
目的:增强EmployeeServiceImpl中的save和update方法.
做什么增强:
1:在调用save方法之前:开启事务:
2:正常调用完save方法之后:提交事务:
3:如果调用save方法出现异常:回滚事务:

//参数构造函数 !importent
@AllArgsConstructor
public class EmployeeServiceWrapper implements IEmployeeService{

    private IEmployeeService employeeService;
    private TransactionManager transactionManager;

    @Override
    public void save() {
        try {
            transactionManager.begin();
            employeeService.save();
            transactionManager.commit();
        }catch (Exception e){
            e.printStackTrace();
            transactionManager.rollback();
        }
    }

    @Override
    public void update() {
        try {
            transactionManager.begin();
            employeeService.update();
            transactionManager.commit();
        }catch (Exception e){
            e.printStackTrace();
            transactionManager.rollback();
        }
    }
}
public class App {
    @Test
    public void  testApp() throws Exception {
        IEmployeeService service=new EmployeeServiceImpl();
        TransactionManager transactionManager=new TransactionManager();
        EmployeeServiceWrapper wrapper=new EmployeeServiceWrapper(service,transactionManager);
        wrapper.save();
        wrapper.update();
    }
}

装饰设计模式在这里存在的问题

1):确实可以这个解决问题.
2):会暴露真实对象–不安全.
3):需要为每一个需要增强的类定义一个包装类

静态代理

//静态代理类
public class EmployeeServiceStaticProxy implements IEmployeeService{
    //没有上面的构造函数,需要添加setter方法     !importent
    @Setter
    private IEmployeeService target;//真实对象
    @Setter
    private TransactionManager transactionManager;

    @Override
    public void save() {
        try {
            transactionManager.begin();
            target.save();
            transactionManager.commit();
        }catch (Exception e){
            e.printStackTrace();
            transactionManager.rollback(e);
        }
    }

    @Override
    public void update() {
        try {
            transactionManager.begin();
            target.update();
            transactionManager.commit();
        }catch (Exception e){
            e.printStackTrace();
            transactionManager.rollback(e);
        }
    }
}
  <!-- 事务代理-->
       <bean id="transactionManager" class="gzcPro.spring._09._staticproxy.manager.TransactionManager"/>

       <!-- 静态代理-->
       <bean id="employeeServiceStaticProxy" class="gzcPro.spring._09._staticproxy.proxy.EmployeeServiceStaticProxy">
              <property name="transactionManager" ref="transactionManager"></property>
              <property name="target">
                     <bean id="employeeService" class="gzcPro.spring._09._staticproxy.service.EmployeeServiceImpl"/>
              </property>
       </bean>
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("App-context09.xml")
public class App {

    @Autowired
    private IEmployeeService proxy;
    @Test
    public void  test() throws Exception {
        proxy.save();
    }
}

静态代理(proxy):在程序运行前就已经存在代理类的字节码文件,代理对象和真实对象的关系在程序运行前就确定了。
静态代理优缺点:
优点:业务类只需要关注业务逻辑本身,保证了业务类的重用性。
缺点:
1.代理对象的某个接口只服务于某一种类型的对象,也就是说每一个真实对象都得创建一个代理对象。
2.如果需要代理的方法很多,则要为每一种方法都进行代理处理。
3.如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
如果期望一个代理类就可以代理多个真实对象------->动态代理.

JDK动态代理

/**
 * Created by gzc on 2019/8/5.
 */
public class TransactionHandler implements InvocationHandler {

    @Setter
    private TransactionManager manager;
    @Setter
    private Object target;//真是对象

    //获取代理对象
    public <T> T getProxy(){
        System.out.println(target.getClass());
        return (T) Proxy.newProxyInstance(
                TransactionHandler.class.getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    /**
     * h.invoke   (h:this)
     *实现代理功能的方法
     *proxy 代理的对象
     * method 代理方法 update 或者save 当前执行的代理方法
     * args 代理方法的参数
     *
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object ret = null;
        //事务的开启
        try {
            manager.begin();
            ret = method.invoke(target,args);
            manager.commit();
        }catch (Exception e) {
            e.printStackTrace();
            manager.rollback(e);
        }

        return ret;
    }
}

<!-- 事务代理-->
       <bean id="transactionManager" class="gzcPro.spring._09._staticproxy.manager.TransactionManager"/>

       <!-- 静态代理-->
       <bean id="transactionHandler" class="gzcPro.spring._09.proxyHander.TransactionHandler">
              <property name="manager" ref="transactionManager"></property>
              <property name="target">
                     <!--private Object target;//真对象-->
                     <bean class="gzcPro.spring._09._staticproxy.service.EmployeeServiceImpl"/>
              </property>
       </bean>
 @Autowired
    private TransactionHandler handler;
    @Test
    public void  testSave() throws Exception {
        IEmployeeService proxy = handler.getProxy();
        System.out.println(proxy.getClass());
        proxy.save();
    }

动态代理类是在程序运行期间由JVM通过反射等机制动态的生成的,所以不存在代理类的字节码文件。代理对象和真实对象的关系是在程序运行事情才确定的。
JDK动态代理API分析:(只能对接口进行代理)
1、java.lang.reflect.Proxy 类:
Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
主要方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler hanlder)
方法职责:为指定类加载器、一组接口及调用处理器生成动态代理类实例
参数:
loader :类加载器
interfaces :模拟的接口
hanlder :代理执行处理器
返回:动态生成的代理对象
2、java.lang.reflect.InvocationHandler接口:
public Object invoke(Object proxy, Method method, Object[] args)
方法职责:负责集中处理动态代理类上的所有方法调用
参数:
proxy :生成的代理对象
method :当前调用的真实方法对象
args :当前调用方法的实参
返回: 真实方法的返回结果
jdk动态代理操作步骤
① 实现InvocationHandler接口,创建自己增强代码的处理器。
② 给Proxy类提供ClassLoader对象和代理接口类型数组,创建动态代理对象。
③ 在处理器中实现增强操作。

JDK动态代理存在的问题:

JDK动态代理:
1,代理的对象必须要实现接口;
2,需要为每个对象创建代理对象;
3,动态代理的最小单位是类(所有类中的方法都会被处理);

CGLIB动态代理

public class TransactionHandler implements org.springframework.cglib.proxy.InvocationHandler {

    @Setter
    private TransactionManager manager;
    @Setter
    private Object target;//真是对象

    //获取代理对象
    public <T> T getProxy(){

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());
        enhancer.setCallback(this);
        return (T) enhancer.create();
    }

    /**
     * h.invoke   (h:this)
     *实现代理功能的方法
     *proxy 代理的对象
     * method 代理方法 update 或者save 当前执行的代理方法
     * args 代理方法的参数
     *
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object ret = null;
        //事务的开启
        try {
            manager.begin();
            ret = method.invoke(target,args);
            manager.commit();
        }catch (Exception e) {
            e.printStackTrace();
            manager.rollback(e);
        }

        return ret;
    }
}

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("App-context09.xml")
public class App {

    @Autowired
    private TransactionHandler handler;
    @Test
    public void  testSave() throws Exception {
        IEmployeeService proxy = handler.getProxy();
        //class gzcPro._gzc01._09._staticproxy.service.EmployeeServiceImpl$$EnhancerByCGLIB$$333160c2
        System.out.println(proxy.getClass());
        proxy.save();
    }

    @Test
    public void  testUpdate() throws Exception {
        IEmployeeService proxy = handler.getProxy();
        //class gzcPro._gzc01._09._staticproxy.service.EmployeeServiceImpl$$EnhancerByCGLIB$$333160c2
        System.out.println(proxy.getClass());
        proxy.update();
    }

}

原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
CGLIB代理总结:
1,CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。
2,要求类不能是final的,要拦截的方法要是非final、非static、非private的。
3,动态代理的最小单位是类(所有类中的方法都会被处理);

在Spring中:
若目标对象实现了若干接口,Spring就会使用JDK动态代理。
若目标对象没有实现任何接口,Spring就使用CGLIB库生成目标对象的子类。
对接口创建代理优于对类创建代理,因为会产生更加松耦合的系统,也更符合面向接口编程规。
cglib和javassist代理的机制都是一样的,都是通过继承实现的.

在上述的操作中,已经实现了动态的为目标对象做功能增强?
为什么还要学Spring的AOP呢?
原因之一是:在为N个service提供代理的时候,我们需要在xml中配置N次

AOP

package gzcPro.spring._09._staticproxy.manager;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * Created by gzc on 2019/8/4.
 */

@Component
@Aspect
public class TransactionManager {

    @Pointcut("execution(* gzcPro.spring._09._staticproxy.service.*Service.*(..))")
    public void pc(){

    }
//    @Before("pc()")
    public void begin(){
        System.out.println("开启一个事务");
    }
//    @AfterReturning("pc()")
    public void commit(){
        System.out.println("提交一个事务");
    }
//    @AfterThrowing(value = "pc()",throwing = "ex")
    public void rollback(Throwable ex){
        System.out.println("回滚一个事务"+ex.getMessage());
    }
//    @After("pc()")
    public void close(){
        System.out.println("关闭一个事务");
    }


    @Around("pc()")//@Before("pc()") @AfterReturning("pc()") @AfterThrowing(value = "pc()",throwing = "ex")@After("pc()")
    public Object  allInOne(ProceedingJoinPoint point){
        Object ret = null ;
        try {
            begin();
            ret = point.proceed();
            commit();

        } catch (Throwable throwable) {
            rollback(throwable);

        } finally {
            close();
        }

        return ret;


    }
}

AOP的目的:

AOP能够将那些与业务无关,却为业务模块所共同调用的逻辑或责任(例如事务处理、日志管理、权限控制等)封装起来,
便于减少系统的重复代码,降低模块间的耦合度,并有利于未来的可拓展性和可维护性。
说人话:把业务方法中与业务无关的操作抽离到不同的对象的方法中,最后使用动态代理的方式组合起来

AOP的优势:

降低模块的耦合度、使系统容易扩展、更好的代码复用性.
Spring的AOP使用动态代理实现:
如果一个类实现了接口,那么spring就使用JDK的动态代理完成AOP;
如果一个类没有实现接口,那么spring就是用cglib完成AOP;

AOP当中的概念:
1、切入点(Pointcut):在哪些类,哪些方法上切入(where);: [在employeServiceImpl 类—>save方法]
2、增强(Advice): 早期翻译为通知,在方法执行的什么时机(when:方法前/方法后/方法前后)做什么(what:增强的功能);[在save方法执行前(when),开启事务(what)]
3、切面(Aspect): 切面=切入点+增强,通俗点就是:在什么时机,什么地点,做什么增强!
[在employeServiceImpl 类—>save方法(where)执行前(when)做开启事务操作(what)]
4、织入(Weaving): 把切面加入到对象,并创建出代理对象的过程。(该过程由Spring来完成)。

XML配置AOP

Spring配置AOP的准备工作:
1).引入Spring AOP开发依赖的jar包:
spring-aop-4.2.4.RELEASE.jar
aopalliance-1.0.0.jar
aspectjweaver-1.8.7.jar

各种不同的增强:

aop:before(前置增强):在方法执行之前执行增强;
aop:after-returning(后置增强):在方法正常执行完成之后执行增强(中间没有遇到任何异常);
aop:after-throwing(异常增强):在方法抛出异常退出时执行增强代码;
aop:after(最终增强):在方法执行之后执行,相当于在finally里面执行;可以通过配置throwing来获得拦截到的异常信息
aop:around(环绕增强):最强大的一种增强类型。 环绕增强可以在方法调用前后完成自定义的行为,环绕通知有两个要求,
1,方法必须要返回一个Object(返回的结果)
2,方法的第一个参数必须是ProceedingJoinPoint(可以继续向下传递的切入点)

<?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:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

       <!-- 开始DI注解解析程序-->
       <context:annotation-config/>
       <!--<context:component-scan base-package="gzcPro.spring._09._staticproxy"></context:component-scan>-->
       <!--<aop:aspectj-autoproxy/>-->
       <!-- 事务管理对象-->
       <bean id="txManager" class="gzcPro.spring._09._staticproxy.manager.TransactionManager"></bean>
       <!-- 需要增强的真实类-->
       <bean id="employeeService" class="gzcPro.spring._09._staticproxy.service.EmployeeServiceImpl"></bean>

       <aop:config>
              <aop:aspect ref="txManager">
                     <aop:pointcut id="px" expression="execution(* gzcPro.spring._09._staticproxy.service.*Service.*(..))"/>
                     <!--之前-->
                     <aop:before method="begin" pointcut-ref="px"></aop:before>
                     <!--没异常-->
                     <aop:after-returning method="commit" pointcut-ref="px"></aop:after-returning>
                     <!--有异常-->
                     <aop:after-throwing method="rollback" pointcut-ref="px" throwing="ex"></aop:after-throwing>
                     <!--finally-->
                     <aop:after method="close" pointcut-ref="px"></aop:after>

                     <!--环绕增强 将所有的增强合并-->
                     <!--<aop:around method="allInOne" pointcut-ref="px"></aop:around>-->
              </aop:aspect>
       </aop:config>

</beans>

或者

<?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:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

       <!-- 开始DI注解解析程序-->
       <context:annotation-config/>
       <!--<context:component-scan base-package="gzcPro.spring._09._staticproxy"></context:component-scan>-->
       <!--<aop:aspectj-autoproxy/>-->
       <!-- 事务管理对象-->
       <bean id="txManager" class="gzcPro.spring._09._staticproxy.manager.TransactionManager"></bean>
       <!-- 需要增强的真实类-->
       <bean id="employeeService" class="gzcPro.spring._09._staticproxy.service.EmployeeServiceImpl"></bean>

       <aop:config>
              <aop:aspect ref="txManager">
                     <aop:pointcut id="px" expression="execution(* gzcPro.spring._09._staticproxy.service.*Service.*(..))"/>
                     <!--环绕增强 将所有的增强合并-->
                     <aop:around method="allInOne" pointcut-ref="px"></aop:around>
              </aop:aspect>
       </aop:config>

</beans>

或者

<?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:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

       <!-- 开始DI注解解析程序-->
       <context:annotation-config/>
       <!--@Component-->
       <context:component-scan base-package="gzcPro.spring._09._staticproxy"></context:component-scan>
       <!--@Aspect-->
      <aop:aspectj-autoproxy/>
</beans>
 @Autowired
    private IEmployeeService service;
    @Test
    public void  testSave() throws Exception {
        System.out.println(service.getClass());
        service.save();
    }

    @Test
    public void  testUpdate() throws Exception {
        service.update();
    }

class com.sun.proxy.$Proxy16
开启一个事务
回滚一个事务/ by zero
关闭一个事务

开启一个事务
更新一个员工
提交一个事务

发布了6 篇原创文章 · 获赞 0 · 访问量 181

猜你喜欢

转载自blog.csdn.net/hero_chao/article/details/103960277