0. 代理模式 (AOP的原理)

代理模式

Rent:

//形象角色:租房public interface Rent {   public void rent();}

Host:

//实在角色: 房东,房东要出租房子public class Host implements Rent{   public void rent() {       System.out.println("房屋出租");  }}

Proxy:

//代理角色:中介public class Proxy implements Rent {   private Host host;   public Proxy() { }   public Proxy(Host host) {       this.host = host;  }   //租房   public void rent(){       seeHouse();       host.rent();       fare();  }   //看房   public void seeHouse(){       System.out.println("带房客看房");  }   //收中介费   public void fare(){       System.out.println("收中介费");  }}

Client:

//客户类,个别客户都会去找代理!public class Client {   public static void main(String[] args) {       //房东要租房       Host host = new Host();       //中介帮忙房东       Proxy proxy = new Proxy(host);       //你去找中介!       proxy.rent();  }}

剖析:在这个过程中,你间接接触的就是中介,就如同现实生活中的样子,你看不到房东,然而你仍旧租到了房东的房子通过代理,这就是所谓的代理模式。

动态代理的益处:

  • 能够使得咱们的实在角色更加纯正 . 不再去关注一些公共的事件 .
  • 公共的业务由代理来实现 . 实现了业务的分工 ,
  • 公共业务产生扩大时变得更加集中和不便 .

毛病 :

  • 类多了 , 多了代理类 , 工作质变大了 . 开发效率升高 .

1. 代理模式

若有userservice 实现增删查改:

public interface UserService {    public void add();    public void delete();    public void update();    public void query();}public class UserServiceImp implements UserService{    public void add() {        System.out.println("Add User");    }    public void delete() {        System.out.println("Delete User");    }    public void update() {        System.out.println("Update User");    }    public void query() {        System.out.println("Query User");    }}

若是在 add、delete、update、query 增加日志:输入“data operation”.在每个语言中就反复的雷同语句。一个好的办法是将这些额定的操作方法“代理中去”。UserService 专一于相应的操作,其余日志等操作交给Proxy来实现!
UserServiceProxy:

public class UserServiceProxy implements UserService{    //UserService 就是被代理的对象    private UserService userService;    public void setUserService(UserService userService) {        this.userService = userService;    }    public void add() {        log("add");        userService.add();    }    public void delete() {        log("delete");        userService.delete();    }    public void update() {        log("update");        userService.update();    }    public void query() {        log("query");        userService.query();    }    public void log(String msg){        System.out.println("Add "+ msg +" operation");    }}

其中 UserServiceImp 被USerServiceImp代理了。

  • 批改原有代码是大忌。

    长处:
  • 使实在的操作专一,将布告的操作交给代理
  • 能够不便拓展,原有代码不变
毛病:
  1. 一个角色一个代理,若是角色过多,代理也就过多了。
开发个别流程

2. AOP

AOP(面向切面编程):通过预编译方
式和运行期动静代理实现程序性能的对立保护的一种技术。

  • 横切关注点:逾越应用程序多个模块的办法或性能。即是,与咱们业务逻辑无关的,然而咱们须要关注的局部,就是横切关注点。如日志 , 平安 , 缓存 , 事务等等 ....
  • 切面(ASPECT):横切关注点 被模块化 的非凡对象。即,它是一个类。(比方Logger类)
  • 告诉(Advice):切面必须要实现的工作。即,它是类中的一个办法。(Logger类中的一个办法:log())
  • 指标(Target):被告诉对象。
  • 代理(Proxy):向指标对象利用告诉之后创立的对象。(代理类)
  • 切入点(PointCut):切面告诉 执行的 “地点”的定义。(在哪里执行)
  • 连接点(JointPoint):与切入点匹配的执行点。(在哪里执行)



SpringAOP中,通过Advice定义横切逻辑,Spring中反对5种类型的Advice:

2.2 AOP配置(基于Spring的接口实现)

想要应用AOP织入,须要在pox.xml导入一个依赖包!

<dependency>     <groupId>org.springframework</groupId>     <artifactId>spring-aspects</artifactId>     <version>5.3.10</version></dependency>

代码:(下面的案例)

  • Spring的API接口
    UserService 和 UserServiceImp代码如上。
    定义Log 和 AfterLog
// 定义Log 继承MethodBeforeAdvice 接口//public class Log implements MethodBeforeAdvice {    // method: 要执行指标函数的办法    //object :参数    // targert: 指标对象。(被代理的)    public void before(Method method, Object[] args, Object target) throws Throwable {        System.out.println( target.getClass().getName() +"的" + method.getName() +" 被执行了");    }}// 返回后果public class AfterLog implements AfterReturningAdvice {    @Override    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {        System.out.println("执行了"+method.getName() +" 办法; 返回后果为 :" + returnValue);    }}

在Bean.xml 中

<?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:aop="http://www.springframework.org/schema/aop"       xsi:schemaLocation="http://www.springframework.org/schema/beans        https://www.springframework.org/schema/beans/spring-beans.xsd        http://www.springframework.org/schema/aop        https://www.springframework.org/schema/aop/spring-aop.xsd">    <bean id="userService" class="com.service.UserServiceImp"/>    <bean id="log" class="com.log.Log"/>    <bean id="afterLog" class="com.log.AfterLog" />    <aop:config>        <aop:pointcut id="pointcut" expression="execution(* com.service.UserServiceImp.*(..))"/>        <!-- log所在的类曾经实现了MethodBefore、After等接口的办法,这里间接定位到Log类中的办法; afterLog 同理; advice 对应的办法-->        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>        <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut" />    </aop:config></beans>

Test:

    public static void main(String[] args) {        ApplicationContext context =  new ClassPathXmlApplicationContext("applicationContext.xml");        // 动静代理的是接口, 要应用 UserService ,而不是 UserServiceImp        UserService userService = (UserService) context.getBean("userService");        userService.add();    }
  1. 在 <aop:config></config> 配置
  2. <aop:pointcut> 就是切入点(定义的),也就是在哪里插入;expression就是要代理的办法;
  3. <aop:advisor> 告诉,也就是本人定义的,而后援用切入点,pointcut-ref=“pointcut”
2.2 定义类实现AOP

自定义切面

public class DiyPointcut {    public void methodeBefore(){        System.out.println("method before");    }    public void methodAfter(){        System.out.println("method before");    }}

在Beans.xml 中

    <bean id="userService" class="com.service.UserServiceImp"/>    <bean id="log" class="com.log.Log"/>    <bean id="afterLog" class="com.log.AfterLog" />  <bean id="diy" class="com.diy.DiyPointcut"/>    <aop:config>        <!--自定义切面, ref 援用到类-->        <aop:aspect ref="diy">           <!-- 切入点-->            <aop:pointcut id="pointcut" expression="execution(* com.service.UserServiceImp.*(..))"/>            <!-- 告诉-->            <aop:before method="methodAfter" pointcut-ref="pointcut"/>            <aop:after method="methodeBefore" pointcut-ref="pointcut"/>        </aop:aspect>    </aop:config>
  • 其中,<aop:aspect> 切面,对象为类(我么自定义的),通过 ref 援用
  • <aop:pointcut> 切入点
  • <aop:before> 在办法之前执行;比照下面的Log,这个办法放在Log外面类中执行的
  • <aop:brefore> 同样的情理

Test:

    public static void main(String[] args) {        ApplicationContext context =  new ClassPathXmlApplicationContext("applicationContext.xml");        // 动静代理的是接口, 要应用 UserService ,而不是 UserServiceImp        UserService userService = (UserService) context.getBean("userService");        userService.add();    }
2.3 注解实现AOP
@Aspectpublic class AnnotationPoint {    @Before("execution(* com.service.UserServiceImp.*(..))")    public void before(){        System.out.println("opeation before");    }}
  • @Aspect 应用注解设置切面(对上小姐的 <aop:aspect>)
  • @Before 对应 <aop:before> (告诉:advice),外面的参数对应切入点(pointcut)。

应用注解在 Beans.xml, 须要开启注解:
<aop:aspectj-autoproxy />

  <bean id="annotationPointcut" class="com.diy.AnnotationPoint"/>  <aop:aspectj-autoproxy />