共计 5668 个字符,预计需要花费 15 分钟才能阅读完成。
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 代理了。
-
批改原有代码是大忌。
长处:
- 使实在的操作专一,将布告的操作交给代理
- 能够不便拓展,原有代码不变
毛病:
- 一个角色一个代理,若是角色过多,代理也就过多了。
开发个别流程
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();} |
- 在 <aop:config></config> 配置
- <aop:pointcut> 就是切入点(定义的),也就是在哪里插入;expression 就是要代理的办法;
- <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
@Aspect | |
public 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 /> |
正文完