3.1. 代理模式
3.1.1. 静态代理
静态代理角色分析
-
抽象角色 : 一般使用接口或者抽象类来实现
-
真实角色 : 被代理的角色
-
代理角色 : 代理真实角色 ; 代理真实角色后 , 一般会做一些附属的操作 .
-
客户 : 使用代理角色来进行一些操作 .
举个实际中的例子:租客通过房产中介进行租房的活动。对应到上面的角色分析,租房行为对应抽象角色,真实角色对应房东,代理角色对应中介,租客对应客户。
public interface Rent {
void rent();
}
public class Host implements Rent{
@Override
public void rent() {
System.out.println("I hava a room to rent");
}
}
public class RentProxy implements Rent{
private Host host;
public RentProxy() {
}
public RentProxy(Host host) {
this.host = host;
}
@Override
public void rent() {
host.rent();
sign();
}
// 代理类的附加行为
public void sign(){
System.out.println("I can sign a contract");
}
}
public class consumer {
public static void main(String[] args) {
RentProxy rentProxy = new RentProxy(new Host());
rentProxy.rent();
}
}
优点:可以对已有的功能进行增强而不用对已有代码进行改动
缺点:增大代码量,每一个需要代理的类都必须要用一个代理类
结合上如问题,引申出动态代理的实现方法。
3.1.2. 动态代理
-
动态代理的角色和静态代理的一样 .
-
动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
-
动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
-
基于接口的动态代理----JDK动态代理
-
基于类的动态代理--cglib
-
现在用的比较多的是 javasist 来生成动态代理
-
3.1.2.1. JDK动态代理
核心 : InvocationHandler 和 Proxy
public class ProxyInvocationHandler implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(rent, args);
return result;
}
}
一个动态代理 , 一般代理某一类业务
3.1.2.2. CGLIB动态代理
核心:MethodInterceptor和Enhancer
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("这里是对目标类进行增强!!!");
Object result = methodProxy.invokeSuper(o, objects);
return result;
}
}
public class Client {
public static void main(String[] args) {
//创建Enhancer对象,类似于JDK动态代理的Proxy类,下一步就是设置几个参数
Enhancer enhancer = new Enhancer();
//设置目标类的字节码文件
enhancer.setSuperclass(Dog.class);
//设置回调函数
enhancer.setCallback(new CglibProxy());
//这里的creat方法就是正式创建代理类
Dog dogProxy = (Dog)enhancer.create();
//调用代理类的shout方法
dogProxy.shout();
}
}
3.1.3. AOP
AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
3.1.3.1. 核心概念
-
横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....
-
切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。
-
通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。
-
目标(Target):被通知对象。
-
代理(Proxy):向目标对象应用通知之后创建的对象。
-
切入点(PointCut):切面通知执行的 “地点”的定义。
-
连接点(JointPoint):与切入点匹配的执行点。
SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:
1570025522824.png3.1.3.2. 案例说明
public interface UserService {
void add();
void delete();
void update();
void select();
}
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("ADD方法执行");
}
@Override
public void delete() {
System.out.println("DELETE方法执行");
}
@Override
public void update() {
System.out.println("UPDATE方法执行");
}
@Override
public void select() {
System.out.println("SELECT方法执行");
}
}
// AOP增强类
public class Log implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被执行了");
}
}
public class Client {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = context.getBean("userService",UserService.class);
userService.add();
}
}
其他说明:
<aop:aspectj-autoproxy />
有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。
网友评论