A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小石姐姐 于 2018-7-31 10:48 编辑

springAop(核心)


Spring Aop(核心)
必须掌握:概念:
连接点     joinpoint 可能被增强的方法,一般在目标对象中定义

目标对象   target    要被增强的对象,增强该对象的方法
切点         pointcut      要被增强的方法
增强/通知  advice    具体对方法做哪些增强
切面       aspect     切点+通知/增强
代理对象   proxy      被增强后的对象,执行具体方法的时候是执行该对象的方法
AOP底层实现:JDK动态代理:
[Java] 纯文本查看 复制代码
注意:被代理的对象必须要实现接口!!!!!
参考以前动态代理的编程
//创建一个使用jdk的proxy完成动态代理的工具
public class JDKProxyFactory implements InvocationHandler {
    //创建代理和invoke方法都需要target,所以在创建时直接传入
    private Object target;
    public JDKProxyFactory(Object target) {
       this.target = target;
    }
    
     // 创建代理对象
    public Object createProxy() {
       ClassLoader loader = target.getClass().getClassLoader();
       Class[] interfaces = target.getClass().getInterfaces();
       //返回代理对象
       return Proxy.newProxyInstance(loader,interfaces, this);
    }
    
    //this:巧妙的利用了工具具有的target,为InvocationHandler对象设置target
    // 在代理实例上处理方法调用并返回结果。
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       // 功能增强操作
       System.out.println("日志操作....");
       return method.invoke(target, args);
    }
}



public Test{
    @Test
    public void test01(){
         //target:被增强的对象,省略创建,默认含有add方法
       JDKProxyFactoryproxy= new JDKProxyFactory(target);
        //代理对象的任何方法都会去执行*传入的this对象*的invoke方法
        proxy.add();
    }
}
CGLIB动态代理:
注意:
jdk的动态代理只可以为实现接口的类去完成操作,而cglib它可以为没有实现接口的类去做代理,也可以为实现接口的类去做代理。
要单独使用CGLIB,那么需要导入cglib的jar包还需要一个asm相关jar包,但是spring框架的spring-core.jar包中已经集成了cglib与asm

[Java] 纯文本查看 复制代码
public class CglibProxyFactory implements MethodInterceptor {

    private Object target;
    public CglibProxyFactory(Object target) {
       this.target = target;
    }

    // 创建代理对象
    public Object createProxy() {
       Enhancerenhance = new Enhancer();// 1.创建Enhancer
       enhance.setSuperclass(target.getClass());// 2.传递目标对象的Class      
       enhance.setCallback(this);// 3.设置回调操作 (相当于InvocationHandler)
       return enhance.create();
    }

    // 相当于InvocationHandler中的invoke
    @Override
    public Object intercept(Object proxy, Method method, Object[] args, MethodProxymethdoProxy) throws Throwable {
       System.out.println("日志操作....");
       return method.invoke(target, args); // 与jdk的proxy中操作类似
    }
}
Spring AOP编程:关注!!!:
底层:哪一种动态代理
灌入关键字
Spring的传统aop编程(理解各对象关系):AOP中增强的方式:
1.  前置通知  目标方法执行前增强  org.springframework.aop.MethodBeforeAdvice
2.  后置通知  目标方法执行后增强 org.springframework.aop.AfterReturningAdvice
3.  环绕通知  目标方法执行前后进行增强 org.aopalliance.intercept.MethodInterceptor
4.  异常抛出通知 目标方法抛出异常后的增强 org.springframework.aop.ThrowsAdvice
5.  引介通知 在目标类中添加一些新的方法或属性 org.springframework.aop.IntroductionInterceptor

通知需要实现其中的方式接口
导包:
[Java] 纯文本查看 复制代码
导入相关jar包

spring-beans-4.2.4.RELEASE.jar
spring-context-4.2.4.RELEASE.jar
spring-core-4.2.4.RELEASE.jar
spring-expression-4.2.4.RELEASE.jar

//日志相关jar
commons-logging-1.2.jar
log4j-1.2.16.jar

spring-aop-4.2.4.RELEASE.jar

注意:导入aop联盟
com.springsource.org.aopalliance-1.0.0.jar

因为使用aspectJ需要导入相关jar包
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

基于aspectJ切点传统开发(掌握)应用场景:
框架已经具有了成熟的通知,我们只需要给方法绑定
编写目标类:
[Java] 纯文本查看 复制代码
//接口
public interface IOrderService {
       void addOrder();
       void updateOrder();
    }
//实现类
public class OrderServiceImpl implements IOrderService {
    @Override
    public void addOrder() {
        System.out.println("orderService add...");
    }
    @Override
    public void updateOrder() {
        System.out.println("orderService update...");
    }
}
编写通知(Advice):
[Java] 纯文本查看 复制代码
public classOrderHelper implements MethodBeforeAdvice, AfterReturningAdvice,MethodInterceptor {
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("前置通知...");
    }

    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("后置通知...");
    }

    @Override
    public Object invoke(MethodInvocation mi) throws Throwable {
        System.out.println("环绕前....");
        Object value = mi.proceed();
        System.out.println("环绕后....");
        return value;
    }
}
在配置文件中配置aop(五个对象):
<?xml version="1.0"encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:context="http://www.springframework.org/schema/context"
       -------------------配置aop命名空间-------------------------------
       xmlns:aop="http://www.springframework.org/schema/aop"   
       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">
   -----------------------------------------------------------------


   ------------------------配置要对谁增强----------------------------------------------
    <!-- 目标target-->
    <bean id="orderService" class="com.b3a4a.aop.OrderServiceImpl"></bean>
   ------------------------------------------------------------------------------------
   ------------------------配置增强方法的什么功能--------------------------------
    <!-- 通知advice-->
    <bean id="orderServiceAdvice"class="com.b3a4a.aop.OrderHelper"></bean>
   ------------------------------------------------------------------------------------
    <!--以下不需要自己编写-->
    <!-- 使用aop标签来完成切面与切点声明 -->
    <!--完成自动代理,不需要提供名称-->
    <aop:config>
        <!-- 定义切点 配置要被增强的方法 -->
        <aop:pointcut expression="execution(* com.b3a4a.aop.IOrderService.*(..))"
                     id="orderServicePointCut" />
        <!-- 定义切面  将被增强的方法和要增强的功能绑定--->
        <aop:advisor advice-ref="orderServiceAdvice"pointcut-ref="orderServicePointCut" />
    </aop:config>
</beans>

<aop:config>  来声明要对aop进行配置
    <aop:pointcut>   它是用于声明切点(简单说就是对哪些方法进行拦截)
    <aop:advisor>    定义传统的aop的切面,传统的aop切面它只能包含一个切点与一个增强
     
execution  /,eksɪ'kjuːʃ(ə)n/  执行
单元测试
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations= "classpath:applicationContext.xml")
public class AopTest {
   
    //注入时不需要名称了,框架自动
    @Autowired
    private IOrderServiceorderService;

    @Test
    public void test1() {
       orderService.updateOrder();
    }
}
Spring整合aspectj框架实现的aop(掌握):应用场景:
自己定义的通知去绑定方法

AspectJ框架它定义的通知类型有6
1.前置通知Before 相当于BeforeAdvice
2.后置通知AfterReturning相当于AfterReturningAdvice
3.环绕通知Around 相当于MethodInterceptor
4.抛出通知AfterThrowing相当于ThrowAdvice
5.引介通知DeclareParents相当于IntroductionInterceptor
6.最终通知After不管是否异常,该通知都会执行
相比spring 的传统AOPAdvice多了一个最终通知
XML开发:编写目标类:
相同
编写通知:
[Java] 纯文本查看 复制代码
public classUserServiceHelper {
    //由于不需要实现接口,因此需要在配置文件中配置方法
    public void before() {
        System.out.println("前置通知");
    }
   
    public void afterReturning(JoinPoint jp, Object val) {
        System.out.println("后置通知");
    }

  
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("环绕前....");
        Object value = pjp.proceed(); // 执行目标行为
        System.out.println("环绕后....");
        return value;
    }

    public void afterThrowing(Throwable ex) {
        System.out.println("发现了异常。。。。"+ex);
    }
    
    public void after(JoinPoint jp) {
        System.out.println(jp.getSignature().getName());
        System.out.println("最终通知");
    }
}
配置文件中配置AOP
<?xml version="1.0"encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
         -------------------配置aop命名空间-------------------------------
       xmlns:aop="http://www.springframework.org/schema/aop"
      xsi:schemaLocation="
                          http://www.springframework.org/schema/beans[url=http://www.springframework.org/schema/beans/spring-beans.xsd]http://www.springframework.org/schema/beans/spring-beans.xsd[/url]
                           http://www.springframework.org/schema/context[url=http://www.springframework.org/schema/context/spring-context.xsd]http://www.springframework.org/schema/context/spring-context.xsd[/url]
                          http://www.springframework.org/schema/aop[url=http://www.springframework.org/schema/aop/spring-aop.xsd]http://www.springframework.org/schema/aop/spring-aop.xsd[/url]">

    <!-- target -->
    <bean id="bookService" class="com.itnannan.aop.BookServiceImpl"></bean>
    <!-- advice-->
    <bean id="XAdvice" class="com.itnannan.aop.BookServiceHelper"></bean>

    <!-- 使用aop:config来声明  使用aop:aspect来配置切面-->
    <!--
  Proxy-target-class默认值是false,代表的是如果目标是有接口的使用JDK动态代理,如果没有接口使用cglib.
  proxy-target-class="true" 代表使用cglib动态代理
  -->
    <aop:config proxy-target-class="true">
        <aop:aspect ref="userServiceAdvice">
            <!--不建议定义切点-->
            <aop:pointcut expression="execution(* *.del(..))"id="delPointCut"/>
            <!-- 前置通知-->
            <aop:before method="before" pointcut-ref="delPointCut"/>
            
            <!--建议这样使用,可以保证耦合低,给不同方法增强不同功能-->
            <aop:before method="before" pointcut="execution(* *.del(..))"/>
            <!-- 后置通知-->
            <aop:after-returning method="afterReturning"pointcut="execution(* *.update(..)"/>
            <!-- 环绕通知-->
            <aop:around method="around"  pointcut="execution(**.add(..)"/>
            <!--抛出异常通知 -->
            <aop:after-throwing method="afterThrowing" pointcut="execution(* *.update(..)" throwing="ex"/>
            <!-- 最终通知-->
            <aop:after method="after" pointcut="execution(* *.update(..)"/>
        </aop:aspect>
    </aop:config>
</beans>
单元测试:
相同
Annotation开发编写目标类
相同,不过由于不进行XML配置,所以获得target对象需要@Service:注解创建对象
编写通知:
@Component//用来创建通知对象
@Aspect//声明为切面
public class CustoemrServiceHelper {
    //通知+切点
    @Before(value="execution(* com.itnannan.aspectj_annotation.CustomerService.*(..))")
    public void before(){
       System.out.println("前置通知");
    }
   
    @After("execution(*com.itnannan.aspectj_annotation.CustomerService.*(..))")
    public void after(){
       System.out.println("后置通知");
    }
   
    @Around("execution(*com.itnannan.aspectj_annotation.CustomerServiceImpl.del(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
       System.out.println("环绕前通知");
       Object object = pjp.proceed();
       System.out.println("环绕后通知");
       return object;
    }
   
    // 异常抛出通知
    @AfterThrowing(value = "execution(* *.del(..))",throwing = "ex")
    public void afterThrowing(JoinPoint jp, Throwable ex) {
        System.out.println("异常抛出通知:" + ex);
    }
}
单元测试:
相同




1 个回复

倒序浏览
沙发是我的了
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马