Sprin框架的学习(课时七)SpringAop的学习(二)

简介: Sprin框架的学习(课时七)SpringAop的学习(二)

案例一

//案例一
public interface Rent {
public class Host implements Rent{
public class Proxy implements Rent {
//案例三
public interface Rent {
public class Host implements Rent {
public class ProxyInvocationHandler implements InvocationHandler {

在案例三的基础上来了案例四  在动态代理中总结出了公式

package coms.Design.Mode.Demo04;
import coms.Design.Mode.Demo03.Rent;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
 * 等会用这个类自动生成代理类
 */
//处理代理实例并返回的结果
public class ProxyInvocationHandler implements InvocationHandler {
    //被代理的接口
    private Object target;
    public void setTarget(Object target) {
        this.target = target;
    }
    //生成代理类 固定代码
    public Object getProxy() {
// 类的位置  接口  应用对象
        return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动代代理的机制本质又是反射机制
        log(method.getName());
        Object result = method.invoke(target, args);
        return result;
    }
//全自动化
    public  void log(String msg){
        System.out.println("执行了陌陌"+msg+"方法");
    }
}

案例四的运行结果

 

动态代理的总结:

●动态代理和静态代理角色- -样


●动态代理的代理类是动态生成的,不是我们直接写好的!


●动态代理分为两大类:基于接口的动态代理 ,基于类的动态代理。基于接口-- JDK动态代理[我们在这里使用]


) 基于类: glib


java字节码实现: javasist


需要了解两个类: Proxy: 代理,InvocationHandler:

第三部分 Spring框架中的Aop@理解Aop的基础概念@了解Aop开发的三种方式 备注Spring框架的学习基于了解Maven项目的前提下开始的哦!


提供声明式事务;允许用户自定义切面==


●横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志,安全,缓存,事务等等....


●切面(ASPECT) :横切关注点被模块化的特殊对象。即,它是一个类。


●通知(Advice) :切面必须要完成的工作。即,它是类中的一-个方法。


●目标(Target) :被通知对象。


●代理(Proxy) :向目标对象应用通知之后创建的对象。


●切入点(PointCut) :切面通知执行的“地点”的定义。


●连接点(JointPoint) :与切入点匹配的执行点。


 


项目的结构

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>spring0909</groupId>
    <artifactId>Com.Spring</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>Spring-01-aop</module>
    </modules>
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.0.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

上面的代码是Com.Spring项目的pom.xml文件要的依赖

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>Com.Spring</artifactId>
        <groupId>spring0909</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>
    <artifactId>Spring-01-aop</artifactId>
    <dependencies>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.4</version>
        </dependency>
    </dependencies>
</project>

上面的代码是Spring-01-aop项目的pom.xml文件要的依赖


在SpringAop中扩展一个知识execution表达式这个是关于SpringAop的一个知识点下面的内容只是扩展内容


一、Aspect切入点语法定义

在使用spring框架配置AOP的时候,不管是通过XML配置文件形式,还是注解的方式都需要定义pointcut(切入点),pointcut称之为切入点。


例如 :


定义切入点表达式  :

execution (* com.sample.service.impl..*.*(..))

上面的execution()是最常用的切点函数,其语法如下所示:


整个表达式可以分为五个部分


1、execution():表达式主体。

2、第一个*号:表示返回类型,*号表示所有的类型。

3、包名:表示需要拦截的包名,后面的两个句点分别表示当前包和当前包的所有子包,com.sample.service.impl包、子孙包下所有类的方法。

4、第二个*号:表示类名,*号表示所有的类。

5、*(..) :第三个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数。

下面给出一些常见切入点表达式的例子: 借鉴(https://smallbee.iteye.com/blog/2213078)


任意公共方法的执行:


execution(public * *(..))    : 表明任何返回类型、类名和参数的任何公共方法都将被通知。

任何一个以"set"开始的方法的执行:


execution(* set*(..))

AccountService接口的任意方法的执行:


execution(* com.xyz.service.AccountService.*(..))

定义在service包里的任意方法的执行:


execution(* com.xyz.service.*.*(..))

定义在service包或者子包里的任意类的任意方法的执行:


execution(* com.xyz.service..*.*(..))


二、如何定义多个切入点,在多个表达式之间如何表示

使用 ||,   or表示 或

使用 &&,and表示 与

使用not,!表示 非


三、execution表达式

1、匹配指定包下所有类方法 :


execution(* com.baidu.dao.*(..)) 不包含子包

2.   匹配指定包以及及指定包下面的子包所有类 :


execution(* com.baidu.dao..*(..))  ..*表示当前包、子孙包下所有类

3、匹配指定类所有方法 :


execution(* com.baidu.service.UserService.*(..))

4、匹配实现特定接口所有类方法 :


execution(* com.baidu.dao.GenericDAO+.*(..))

5、匹配所有save开头的方法 :


execution(* save*(..))

另外,签名可分为类型签名和方法签名,下面介绍两种类型 的区别,参考自: https://www.jianshu.com/p/1ff6c1edbb7b


四、类型签名表达式

为了根据类型(比如接口、类名或者包名过滤方法),SpringAOP提供了Within关键字。类型签名模式如下,其中可以使用package name或者class name替换type name。


Within()

接下来列举一些类型签名用法的示例:


within(net.yangki..*):该通知将匹配net.yangki包及其子包中所有类中的所有方法。

within(net.yangki.spring.demo.MyService):该通知将匹配MyService类中的所有方法。

within(MyServiceInterface+):该通知将匹配所有实现了MyServiceInterface接口的类的所有方法。

within(net.yangki.spring.demo.MyBaseService+):该通知将匹配MyBaseService类以及其子类的所有方法。

五、方法签名表达式

如果想根据方法签名进行过滤,可以使用关键字execution。模式如下:


execution(.*(parameters))

此时,对于与给定的作用域、返回类型、完全限定类名以及参数相匹配的方法,都会应用指定的通知。方法的作用域可以是公共的、保护的或者私有的。如果不想使用参数过滤,可以指定两个点..,以表明方法可以接受任何数量和任何类型的参数。下面对方法签名的示例进行了简单的概述:


execute(* net.yangki.soring.demo.MyBean.*(..)):该通知将匹配MyBean中的所有方法。

execute(public * net.yangki.spring.demo.MyBean.*(..)):该通知将匹配MyBean中的所有公共方法。

execute(public String net.yangki.spring.demo.MyBean.*(..)):该通知将匹配MyBean中的所有返回值为String类型的公共方法。

execute(public * net.yangki.spring.demo.MyBean.*(long,..)):该通知将匹配MyBean第一个参数被定义为long的所有公共方法。


六、其他替代的切入点指示符

该部分将举例SpringAOP所支持的指示符。AOP仅支持在其他AOP项目中可用的指示符的一个子集。


bean(* Service):根据名称使用关键字bean进行过滤。该切入点表达式将与名称中带有后缀Service的Bean相匹配。

@annotation(net.yangki.spring.demo.MarkerMethodAnnotation):根据所应用的注解对方法进行过滤。该切入点表达式表明使用了MarkerMethodAnnotation注解的方法将被通知。

within(net.yangki.spring.demo.MarkerAnnotation):当带有关键字within的切入点表达式与一个包、类或者接口相匹配时,可以根据类所使用的注解限制对类的过滤。此时,使用了MarkerMethodAnnotation注解的类将被@within关键字通知。

This(net.yangki.spring.demo.MarkerInterface):该切入点表达式将对任何实现了MarkerInterface接口的代理对象的方法进行过滤。

七、通配符

在定义表达式时,还可以使用通配符。比如*、..或者+。如下表


通配符    定义

.. 该通配符匹配方法定义中的任何数量的参数,此外还匹配类定义中任何数量的包

+  该通配符匹配给定类的任何子类

*  该通配符匹配任何数量的字符


SpringAop书写的三种方式 注解  配置文件 自定义类中接下来我们来实战一下吧

方案一 注解的方式来表达学习 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"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       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
          http://www.springframework.org/schema/tx
          http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!--注册Bean-->
    <bean id="userservice" class="com.service.UserServiceImp"></bean>
    <bean id="log" class="log.Log"></bean>
    <bean id="afterlog" class="log.Afterlog"></bean>
<!--方式三 -->
    <bean id="annotationPointCut" class="diy.AnnotationPointCut"></bean>
    <!--代理Aop注解支持 JDK  proxy-target-class="false" -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
package diy;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
/**
 * 方式三 使用注解方式实现Aop
 */
//@Aspect 标注这个类是切面
/**
 * @Before("execution(* com.service.UserServiceImp.*(..))")
 *  @After("execution(* com.service.UserServiceImp.*(..))")
 */
@Aspect
public class AnnotationPointCut {
    @Before("execution(* com.service.UserServiceImp.*(..))")
    public void before() {
        System.out.println("==============方法执行前=================");
    }
    @After("execution(* com.service.UserServiceImp.*(..))")
    public void after() {
        System.out.println("==============方法执行后==================");
    }
    @Around("execution(* com.service.UserServiceImp.*(..))")
    public  void  around(ProceedingJoinPoint jp) throws Throwable {
        System.out.println("在环绕增强中,我们可以定义一个参数,代表我们要获取处理的切入点");
        Object o = jp.proceed();
        System.out.println("环绕前");
    }
}

方式案二 利用自己自定义的类中来表达

package diy;
/**
 * 自定义类
 */
public class DiyPointcut {
    public  void  before(){
        System.out.println("==============方法执行前=================");
    }
    public  void  after(){
        System.out.println("==============方法执行后==================");
    }
    public  void  see(){
        System.out.println("SpringAop开发第二种方案自定义类");
    }
}
 <bean id="diy" class="diy.DiyPointcut"></bean>
    <aop:config>
        <!--自定义切面 ref 要引用的类-->
        <aop:aspect ref="diy">
            <!--切入点-->
           <aop:pointcut id="point" expression="execution(* com.service.UserServiceImp.*(..)))"/>
            <!--通知-->
            <aop:before method="before" pointcut-ref="point"></aop:before>
            <aop:after method="after" pointcut-ref="point"></aop:after>
            <aop:after method="see" pointcut-ref="point"></aop:after>
        </aop:aspect>
    </aop:config>

方案三 利用原始方法在配置文件中

package com.service;
public interface UserService {
    public  void  add();
    public  void  delete();
    public  void  update();
    public  void  query();
}
package com.service;
public class UserServiceImp  implements UserService{
    @Override
    public void add() {
        System.out.println("增加了一个用户");
    }
    @Override
    public void delete() {
        System.out.println("删除了一个用户");
    }
    @Override
    public void update() {
        System.out.println("修改了一个用户");
    }
    @Override
    public void query() {
        System.out.println("查询了一个用户");
    }
}
package log;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
public class Afterlog  implements AfterReturningAdvice {
    /**
     * 多了一个返回值
     * @param o
     * @param method
     * @param objects
     * @param o1
     * @throws Throwable
     */
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("执行了"+method.getName()+"返回了"+o);
    }
}
package log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log  implements MethodBeforeAdvice {
    //Method 要执行的目标对象方法
    //orgs  参数
    //target 目标对象
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}
import com.service.UserService;
import com.service.UserServiceImp;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MaTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理的是接口
        UserService userservice = (UserService) applicationContext.getBean("userservice");
        userservice.add();
    }
}
import com.service.UserService;
import com.service.UserServiceImp;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class MaTest {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
//动态代理的是接口
        UserService userservice = (UserService) applicationContext.getBean("userservice");
        userservice.add();
        userservice.delete();
        userservice.query();
        userservice.update();
    }
}

                   

相关文章
|
Java 程序员 应用服务中间件
【推荐】深入浅出学习Spring框架【上】
【推荐】深入浅出学习Spring框架【上】
60 0
|
7月前
|
XML 缓存 Java
大厂面试攻略:Spring框架核心要点精讲
Java SPI (Service Provider Interface) 是一种服务发现机制,允许在运行时动态加载和发现服务提供者。在数据库驱动加载中,SPI使得数据库驱动能够自动识别和注册,而无需显式加载。 Spring 是一个广泛应用的轻量级框架,核心功能包括依赖注入(DI)和面向切面编程(AOP)。不使用Spring时,开发人员需要手动管理对象的创建和依赖关系,使用Servlet等基础组件完成Web开发,以及手动处理JDBC操作。Spring通过管理Bean的生命周期和依赖关系,简化了企业级应用的开发,降低了代码的侵入性。
90 1
大厂面试攻略:Spring框架核心要点精讲
|
6月前
|
缓存 安全 Java
Shiro框架的知识点一网打尽,生命不息,学习不止
Shiro框架的知识点一网打尽,生命不息,学习不止
57 0
|
8月前
|
Java 数据库连接 数据库
Java大数据开发工程师__Spring学习笔记(待更新)
Java大数据开发工程师__Spring学习笔记(待更新)
61 1
|
8月前
|
Java Spring 容器
Spring框架讲解笔记:spring框架学习的要点总结
Spring框架讲解笔记:spring框架学习的要点总结
|
8月前
|
Java Spring 容器
spring讲解笔记:spring框架学习的要点总结
spring讲解笔记:spring框架学习的要点总结
|
存储 监控 Java
【推荐】深入浅出学习Spring框架【中】
【推荐】深入浅出学习Spring框架【中】
43 0
|
Java 数据库连接 数据库
spring高级源码笔记:深入理解阿里spring源码核心思想及框架应用
Spring 是分层的 full-stack(全栈) 轻量级开源框架,以 IoC 和 AOP 为内核,提供了展现层 SpringMVC 和业务层事务管理等众多的企业级应⽤技术,还能整合开源世界众多著名的第三⽅框架和类库,已经成为使⽤最多的 Java EE 企业应⽤开源框架。
235 0
|
设计模式 算法 Java
Sprin框架的学习(课时七)SpringAop的学习(一)
Sprin框架的学习(课时七)SpringAop的学习(一)
82 0

热门文章

最新文章