设计模式-代理模式

1、建立项目,导包(数据库驱动、Mybatis、Spring、Spring和Mybatis整合),配置文件(Spring主配置文件application_context.xml、数据库连接db.properties,日志系统log4j.properties);

2、配置数据源(spring主配置文件中要配置读取配置信息的工具)

<context:property-placeholder location="db.properties" />

3、dataSource→SQLSessionFactoryBean→sqlSessionTemplate→usersServiceImpl

4、SqlSessionDaoSupport的使用(内部有个成员属性sqlSessionFactory)

5、MapperScannerConfigurer,扫描某个包下的Mapper建立bean,不需要每个Mapper都配置bean。

<!--配置MapperScannerConfigurer的bean,会自动扫描basePackage属性值包内的所有对象
    建立UserMapper的bean,供UsersServiceImpl3依赖注入使用 ! -->
    <bean id="mapperScannerConfigurer"
          class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.dyh.mapper" />
    </bean>
    <!--配置Service层的Bean,虽然本配置文件中没有配置usersMapper这个bean,但是
    上面MapperScannerConfigurer已经扫描建立了一系列bean存在SpringIoC容器中-->
    <bean id="usersService" class="com.dyh.service.impl.UsersServiceImpl3">
        <property name="usersMapper" ref="usersMapper" />
    </bean>

1、什么是代理模式

代理模式(Proxy Pattern):代理模式是 Java 常见的设计模式之一。所谓代理模式是指客户端并不直接调用实际的对象,而是通过调用代理对象,来间接的调用实际的对象。通俗的来讲代理模式就是我们生活中常见的中介。

2、为什么使用代理模式

隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。

开闭原则:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。

2.1 代理模式的优点

代理模式能将代理对象与真实对象被调用的目标对象分离。

一定程度上降低了系统的耦合度,扩展性好。

保护目标对象。

增强目标对象。

2.2 代理模式的缺点

代理模式会造成系统设计中类的数目的增加。

在客户端和目标对象增加一个代理对象,会造成请求处理速度变慢。

增加了系统的复杂度。

3、代理模式的实现

代理模式可以分为两种:静态代理、动态代理。

3.1 静态代理

静态代理模式由三个部分构成:

一个公共的接口

一个被代理角色

一个代理角色

3.1.1 公共接口

接口:定义一种规范和标准,是共性行为的抽象。例如出租。

 

package staticproxy;

/**
 * 出租 接口:行为规范
 */
public interface Rent {
    void renting();
}

3.1.2 代理角色

隔壁老王有房要出租,实现出租接口。

package staticproxy;

/**
 * 房东
 */
public class FangDong implements Rent{
    @Override
    public void renting() {
        System.out.println("XXX小区XX室X厅 tel:xxxx");
    }
}

3.1.3 代理角色

房屋中介,帮人代理租房。

package staticproxy;

/**
 * staticproxy  静态代理  房屋中介
 */
public class StaticProxy implements  Rent {
    private Rent fangDong;      // 委托者

    public StaticProxy(Rent fangDong) {
        this.fangDong = fangDong;
    }

    @Override
    public void renting() {
        System.out.println("带客户看房");
        this.fangDong.renting();        // 委托者的出租要求
        System.out.println("签订合同,收取租金,收取服务费");
    }
}

3.1.4 创建测试类

package staticproxy;

/**
 * 客户调用测试
 */
public class TestStaticProxy {
    public static void main(String[] args) {
        Rent fd = new FangDong();       // 委托者,实际房东
        StaticProxy staticProxy = new StaticProxy(fd);// 房屋中介
        staticProxy.renting();
    }
}

运行结果:

3.2 动态代理的实现

在动态代理中分为两种实现方式:

使用 JDK 的 Proxy 类实现动态代理

使用 CGLIB 实现动态代理

3.2.1 使用 JDK 的 Proxy 类实现动态代理

3.2.1.1 创建业务接口

 

public  interface  JdkProxyRent  {
	void  renting();
}

3.2.1.2 创建接口实现类

public  class  JdkProxyOldWang  implements  JdkProxyRent  {
	@Override
	public  void  renting()  {
		System.out.println("OldWang  有房出租");
	}
}

3.2.1.3 创建生成代理对象的工厂

public  class  JdkProxyFactory  {
	/**
	*  动态生成代理对象
	*/
	public  static  Object  getProxyBean(Object  target){
		Class  clazz  =  target.getClass();
		MyAspect  myAspect  =  new  MyAspect();
		//在 JDK  中动态生成代理对象的方法
		return  Proxy.newProxyInstance(clazz.getClassLoader(),
				clazz.getInterfaces(),  new  InvocationHandler()  {
			/**
			*  动态生成代理对象中的方法。
			*  @param  proxy  动态生成的代理对象
			*  @param  method  目标方法的方法对象
			*  @param  args  传递到目标方法中的参数列表
			*  @return
			*  @throws  Throwable
			*/
			@Override
			public Object  invoke(Object proxy, Method  method, Object[]
					args)  throws  Throwable  {
				myAspect.before();
				Object  obj  =
				method.invoke(target,args);
				myAspect.after();
				return  obj;
			}
		});
}

3.2.1.4 创建切面对象

public  class  MyAspect  {
	public  void  before(){
		System.out.println("带领房客看房。。。签租房协议");
	}
	public  void after(){
		System.out.println("售后服务。");
	}
}

3.2.1.5 创建测试类

public  class  JdkProxyTest  {
	public  static  void  main(String[]  args)  {
		JdkProxyRent  jdkProxyRent  =  new  JdkProxyOldWang();
		JdkProxyRent  jdkProxyRent1  =  (JdkProxyRent)
					JdkProxyFactory.getProxyBean(jdkProxyRent);
		jdkProxyRent1.renting();
	}
}

3.3.2 使用 CGLIB 实现动态代理

CGLIB(Code Generation Library)是一个高性能开源的代码生成包,它被许多框架所使用,其底层是通过使用一个小而快的字节码处理框架 ASM(Java 字节码操控框架)转换字节码并生成新的类。因此  CGLIB 要依赖于 ASM 的包

JDK 的动态代理机制只能代理实现了接口的类,而对于没有实现接口的类就不能使用JDK 的 Proxy 类生成代理对象,cglib 是针对类来实现代理的,他的原理是对指定的目标类生成一个子类并通过回调的方式来实现增强,但因为采用的是继承,所以不能对 final 修饰的类进行代理

3.3.2.1 添加 jar 包

cglib.jar

asm.jar

3.3.2.2 创建业务接口

public  interface  CglibProxyRent  {
	void  renting();
}

3.3.2.3 创建接口实现类

public  class  CglibProxyOldwang  implements  CglibProxyRent  {
	@Override
	public  void  renting()  {
		System.out.println("Oldwang  有房出租");
	}
}

3.3.2.4 创建生成代理对象的工厂

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()  {
			/**
			*
			*  @param  o  代理对象的引用
			*  @param  method  目标对象的方法对象
			*  @param  objects  目标方法的参数列表
			*  @param  methodProxy  目标方法的方法对象的代理对象
			*  @return
			*  @throws  Throwable
			*/
			@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();
	}
}

3.3.2.5 创建切面

public  class  CglibMyAspect  {
	public  void  before(){
		System.out.println("带领客户看房,签订租房协议");
	}
	public  void  after(){
		System.out.println("售后服务");
	}
}

3.3.2.6 创建测试类

public  class  Test  {
	public  static  void  main(String[]  args)  {
		CglibProxyRent  rent  =  new  CglibProxyOldlu();
		CglibProxyRent  rent1  =  (CglibProxyRent)
		CglibProxyBeanFactory.getProxyBean(rent);
		rent1.renting();
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

暖锋丫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值