AOP(面向切面编程)
代理模式
代理模式:代理模式又叫委托模式,是为某个对象提供一个代理对象,并且由代理对象控制对原对象的访问。代理模式通俗来讲就是我们生活中常见的中介。
分类:
- 静态代理
- 动态代理
静态代理
角色分析:
- 抽象角色:一般回使用接口或者抽象类
- 真实角色:被代理的角色
- 代理角色:代理真实角色,一般会增加一些方法
- 客户:用来访问代理对象
//租房
public interface Rent {
public void rent();
}
//房东
public class Rule implements Rent {
@Override
public void rent() {
System.out.println("房东出租房子");
}
}
//中介
public class Proxy implements Rent{
private Rule rule;
public Proxy() {
}
public Proxy(Rule rule) {
this.rule = rule;
}
@Override
public void rent() {
this.rule.rent();
}
public void fare(){
System.out.println("受中介费");
}
}
public class Client {
public static void main(String[] args) {
//代理
Proxy proxy = new Proxy(new Rule());
proxy.fare();
proxy.rent();
}
}
我们可以看到,客户没有接触到中介,但客户租到了房子。而且中介含加收了中介费。
代理的好处:
- 可以使真实的操作更加的纯粹。
- 公共的方法可以交给代理来实现,实现了业务的分工。
- 公共业务发生扩展的时候,方便集中管理。
缺点:
- 一个真实角色就会产生一个代理角色;代码量就会翻倍开发效率就会变低~
动态代理
-
动态代理何静态代理角色一样
-
动态代理的代理类使动态生成的,不是我们写的,他解决了静态代理的不足
-
动态代理分为两大类:基于接口的动态代理,基于类的动态代理
- 基于接口的–JDK动态代理
- 基于类:cglib
- java字节码实现:javassist
需要了解两个类:
- Proxy
- InvocationHandler(接口)
package cn.guoke; //租房 public interface Rent { public void rent(); }
package cn.guoke;
import 静态代理.Rent;
public class Rule implements Rent {
@Override
public void rent() {
System.out.println("房东出租房子");
}
}
package cn.guoke;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Proxylnvocationhardler implements InvocationHandler {
//被代理的接口
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
//生成代理类
public Object getProxy(){
Proxy.newProxyInstance(this.getClass().getClassLoader(),getClass().getInterfaces(),this);
}
/**
*处理代理实例并返回结果
* @param proxy
* @param method
* @param args
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke = method.invoke(rent, args);
return invoke;
}
}
package cn.guoke;
public class Client {
public static void main(String[] args) {
//真实角色
Rule rule = new Rule();
//代理角色
Proxylnvocationhardler proxylnvocationhardler = new Proxylnvocationhardler();
//通过调用程序处理我们调用的接口对象
proxylnvocationhardler.setRent(rule);
Object proxy = proxylnvocationhardler.getProxy();
}
}
AOP
1、横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点
2、切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象
3、连接点(joinpoint):被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器
4、切入点(pointcut):对连接点进行拦截的定义
5、通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类
6、目标对象:代理的目标对象
7、织入(weave):将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段
使用Spring实现AOP
使用AOP需要导入一个依赖
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
编写接口
package cn.at99guoke.service;
public interface UserService {
public void add();
public void delect();
public void update();
public void select();
}
实现接口
package cn.at99guoke.service;
public class UserServiceImpl implements UserService {
public void add() {
System.out.println("增加一个用户");
}
public void delect() {
System.out.println("删除一个用户");
}
public void update() {
System.out.println("更新一个用户");
}
public void select() {
System.out.println("查询一个用户");
}
}
编写一个log类
package cn.at99guoke.log;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
public class Log implements MethodBeforeAdvice {
/**
*
* @param method 要执行目标对象的方法
* @param objects 参数
* @param o 目标对象
* @throws Throwable
*/
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName()+"的"+method.getName()+"执行了");
}
}
方式一:
配置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
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<bean id="log" class="cn.at99guoke.log.Log"/>
<bean id="userServiceImpl" class="cn.at99guoke.service.UserServiceImpl"/>
<!-- 方式一:使用原生Spring API-->
<!-- 配置aop:需要导入aop约束-->
<aop:config>
<!-- 切入点:execution:表达式(需要执行的位置! * * * * *)-->
<aop:pointcut id="pointcut" expression="execution(* cn.at99guoke.service.UserServiceImpl.*(..))" />
<!-- 执行环绕增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
</aop:config>
</beans>
方式二:
自定义实现:
<bean id="day" class="cn.at99guoke.log.Day"/>
<aop:config>
<!-- 自定义切面-->
<aop:aspect ref="day">
<!-- 切入点-->
<aop:pointcut id="point" expression="execution(* cn.at99guoke.service.UserServiceImpl.*(..))"/>
<!-- 通知-->
<aop:before method="before" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
注解实现