代理模式
代理模式的概念
代理模式(Proxy Pattern):代理模式是 Java 常见的设计模式之一。所谓代理模式是指客 户端并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象。通俗的 来讲代理模式就是我们生活中常见的中介
代理模式的好处
- 隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类 对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
- 开闭原则:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额 外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合 代码设计的开闭原则
- 优点:
- 代理模式能将代理对象与真实对象被调用的目标对象分离。
- 一定程度上降低了系统的耦合度,扩展性好
- 保护目标对象。
- 增强目标对象
- 缺点:
- 代理模式会造成系统设计中类的数目的增加
- 在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢
- 增加了系统的复杂度
静态代理
静态代理:代理类由程序员创建的然后编译成.class文件。但是其中缺点是,具有重复代码,灵活性不好,例如在执行某个接口中所有方法之前加上日志逻辑,那么使用静态代理的话,在代理类中每个方法都得加。 组成:
实现
public interface Rent { void renting(); }
public class Lanh implements Rent {
@Override
public void renting() {
System.out.println("Lanh有房出租");
}
}
public class StaticProxyRent implements Rent {
private Rent rent;
public StaticProxyRent(Rent rent){
this.rent = rent;
}
@Override
public void renting() {
System.out.println("向房客出租房屋");
this.rent.renting();
System.out.println("完成售后服务");
}
}
public class StaticProxyTest {
public static void main(String[] args) {
Rent rent = new Lanh();
StaticProxyRent staticProxyRent = new StaticProxyRent(rent);
staticProxyRent.renting();
}
}
动态代理
动态代理:是在运行的时候,通过jvm中的反射进行动态创建对象,生成字节码对象,传入由我们实现该接口的对象,通过反射创建代理对象。 然后当调用代理对象的任何方法都会调用接口中的 invoke(Object proxy,Method method,Object[] args)传入当前代理对象、当前调用的方法、方法参数值
JDK动态代理
使用 JDK 的 Proxy 类实现动态代理
注意:JDK 的动态代理机制只能代理实现了接口的类,而对于没有实现接口的类就不能使用 JDK 的 Proxy 类生成代理对象
public interface JdkProxyRent { void renting(); }
public class JdkProxyLanh implements JdkProxyRent {
@Override
public void renting() {
System.out.println("Lanh有房出租");
}
}
public class MyAspect {
public void before(){
System.out.println("带领房客看房。。。签租房协议");
}
public void after(){
System.out.println("售后服务。");
}
}
public class JdkProxyFactory {
public static Object getProxyBean(Object target){
Class cls = target.getClass();
MyAspect myAspect = new MyAspect();
return Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
myAspect.before();
Object obj = method.invoke(target,args);
myAspect.after();
return obj;
}
});
}
public class JdkProxyTest {
public static void main(String[] args) {
JdkProxyRent jdkProxyRent = new JdkProxyLanh();
JdkProxyRent proxyRent = (JdkProxyRent) JdkProxyFactory.getProxyBean(jdkProxyRent);
Rent.renting();
}
}
CGLIB动态代理
使用 CGLIB 实现动态代理
注意:cglib 是针对类来实现代理的,他的原理是对指定的目标类生成一个子类并通过回调的方式来实现增强,但因为采用的是继承,所以不能对 final 修饰的 类进行代理
public interface CglibProxyRent { void renting(); }
public class CglibProxyLanh implements CglibProxyRent {
@Override
public void renting() {
System.out.println("Lanh有房出租");
}
}
public class CglibMyAspect {
public void before(){
System.out.println("带领客户看房,签订租房协议");
}
public void after(){
System.out.println("售后服务");
}
}
public class CglibProxyBeanFactory {
public static Object getProxyBean(CglibProxyRent rent){
CglibMyAspect myAspect = new CglibMyAspect();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(rent.getClass());
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
myAspect.before();
Object obj = method.invoke(rent,objects);
myAspect.after();
return obj;
}
});
return enhancer.create();
}
}
public class Test {
public static void main(String[] args) {
CglibProxyRent rent = new CglibProxyLanh();
CglibProxyRent proxyRent = (CglibProxyRent)CglibProxyBeanFactory.getProxyBean(rent);
proxyRent.renting();
}
}
注意:静态代理跟动态代理,在功能上最明显的表现是,静态代理每代理一个新方法,就要写一遍代理(即使是这些代码在其他方法增强时已经写过),动态代理则是同样的代理逻辑的方法均可以使用同一段代码进行代理
AOP
AOP 的全称是 Aspect Oriented Programming,即面向切面编程,它将业务逻辑的各个部 分进行隔离,使开发人员在编写业务逻辑时可以专心于核心业务,从而提高了开发效率。
- 作用:在不修改代码的情况下实现对程序的拓展
- 实现方式
- SpringAOP模块:切面需要实现通知接口
- AspectJ:切面不需要实现通知接口
- Schema-Based:切面需要实现通知接口
Spring中使用AOP模块
使用 org.springframework.aop.framework.ProxyFactoryBean 工厂对象创建代理对象
public interface UsersService { void addUsers(); }
public class UsersServiceImpl implements UsersService {
@Override
public void addUsers() {
System.out.println("addUsers.....");
}
}
public class ToUppercaseAspect implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
Object[] args = methodInvocation.getArguments();
args[0] = ((String)args[0]).toUpperCase();
Object obj = methodInvocation.proceed();
return obj;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="usersService" class="com.lanh.service.impl.UsersServiceImpl"/>
<bean id="toUppercaseAspect" class="com.lanh.aop.ToUppercaseAspect"/>
<bean id="usersServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces" value="com.lanh.service.UsersService"/>
<property name="target" ref="usersService"/>
<property name="interceptorNames">
<list>
<value>toUppercaseAspect</value>
</list>
</property>
<property name="proxyTargetClass" value="true"/>
</bean>
</beans>
public class Test {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UsersService usersService = (UsersService)applicationContext.getBean("usersServiceProxy");
usersService.addUsers();
}
}
AspectJ实现切面
public interface UsersService { void addUsers(String username); }
public class UsersServiceImpl implements UsersService {
@Override
public void addUsers(String username) {
String str = null;
str.toUpperCase();
System.out.println("AddUsers "+username);
}
}
public class MyAspect {
public void myAspectBefore(JoinPoint joinPoint){
System.out.println("MyAspect Before");
}
public void myAspectAfter(JoinPoint joinPoint){
System.out.println("MyAspect After");
}
}
<?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.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="usersService" class="com.lanh.aspectj.service.impl.UsersServiceImpl"/>
<bean id="myAspect" class="com.lanh.aspectj.aop.MyAspect"/>
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="myPointcut" expression="execution(* com.lanh.aspectj.service.*.*(..))"/>
<aop:before method="myBefore" pointcut-ref="myPointcut"/>
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointcut"/>
<aop:around method="myAround" pointcut-ref="myPointcut"/>
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointcut" throwing="e"/>
<aop:after method="myAfter" pointcut-ref="myPointcut"/> </aop:aspect>
</aop:config>
</beans>
Schema-Based
不写了不写了,23:25了,还没吃晚饭、洗澡。这个就留着吧,这叫什么?这叫留白!是经典的写作手法(手动doge)
|