案例一
//案例一 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(); } }