Structural model - proxy mode (seven)

The project source address: https: //github.com/ggb2312/JavaNotes/tree/master/design-pattern (design patterns relevant code and notes)

1. Definitions

Provides a proxy for other objects to control access to this object

2. Applicable scene

  • Protection of the target object
  • Enhanced Audience

3. Proxy Type

Static agents

  • Static proxy is to display the specified proxy code

Dynamic Proxy

  • Dynamic agent can not proxy class, but can proxy interface

CGLib agent

  • When using CGLib agent, because to use inheritance, as well as rewrite, so be sure to pay special attention to the time of this keyword final

Acting speed:
JDK7, JDK8 dynamic proxies faster than CGLib

4. Spring agent selection

When Bean has to implement the interface, Spring will use the JDK dynamic proxy. When Bean does not implement the interface, Spring use CGIib. Can force CGIib, was added in the spring arrangement

The relevant design patterns

Proxy Mode and Decorator

  • Decorator is a plus behavioral targeting, proxy mode is to control access

Adapter mode and proxy mode

  • Changing the mode of the main consideration adapter interface objects, the agent can not change the interface mode is a proxy class.

Example 6. Mode

BACKGROUND: Order libraries

Project structure

6.1 Static Proxy

(1) Orders entity

public class Order {
    private Object orderInfo;
    private Integer userId;

    public Object getOrderInfo() {
        return orderInfo;
    }

    public void setOrderInfo(Object orderInfo) {
        this.orderInfo = orderInfo;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }
}

(2) Dao

Dao layer interfaces:

public interface IOrderDao {
    int insert(Order order);
}

Dao achieve layers:
pretend orders added successfully.

public class OrderDaoImpl implements IOrderDao {
    @Override
    public int insert(Order order) {
        System.out.println("Dao层添加order成功");
        return 1;
    }
}

(3)Service

Service layer interfaces:

public interface IOrderService {
    /** 保存订单,参数为订单对象,返回值为生效行数 */
    int saveOrder(Order order);
}

Service layer implementation:

public class OrderServiceImpl implements IOrderService {

    private IOrderDao iOrderDao;

    @Override
    public int saveOrder(Order order) {
        /** Spring会自己注入,我们这里就直接new出来了 */
        iOrderDao = new OrderDaoImpl();
        System.out.println("Service调用Dao层添加Order层");
        return iOrderDao.insert(order);
    }
}

(4) to achieve sub-library and the static agent

DataSourceContextHolder maintains a database of information

public class DataSourceContextHolder {
    private static final ThreadLocal<String> CONTEXT_HOLDER = new ThreadLocal<>();

    public static void setDBType(String dbType) {
        CONTEXT_HOLDER.set(dbType);
    }

    public static String getDBType() {
        return (String) CONTEXT_HOLDER.get();
    }

    public static void clearDBType() {
        CONTEXT_HOLDER.remove();
    }
}

Spring inside the sub-libraries:

public class DynamicDataSource extends AbstractRoutingDataSource {
    @Override
    protected Object determineCurrentLookupKey() {
        return DataSourceContextHolder.getDBType();
    }
}

There is also a static proxy class:

public class OrderServiceStaticProxy {
    /**  在代理类里面注入目标对象 */
    private IOrderService iOrderService;

    /** 我们要在这静态代理类里面增强这个方法 */
    public int saveOrder(Order order){
        beforeMethod();
        /** 如果这里有spring容器的话,就不用显示的new了 */
        iOrderService = new OrderServiceImpl();
        int userId = order.getUserId();
        /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */
        int dbRouter = userId % 2;
        System.out.println("静态代理分配到【db"+dbRouter+"】处理数据");

        //todo 设置dataSource;
        DataSourceContextHolder.setDBType("db"+dbRouter);

        afterMethod();
        return iOrderService.saveOrder(order);
    }

    /** 我们要增强,我们就来写上一个before和after */
    private void beforeMethod(){
        System.out.println("静态代理 before code");
    }

    private void afterMethod(){
        System.out.println("静态代理 after code");
    }
}

Let orderId in the proxy class to the modulo 2, and the remainder is 0 DB0 into the remainder is placed in a db1. In the spring of dataSource configuration, specify the class as DynamicDataSource , DynamicDataSource from () DataSourceContextHolder.getDBType get into that database needs.

spring configuration when the sub-libraries

//数据库0
<bean id="db0" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
       <property name="driverClassName" value="${db0.driverClassName}"/>
       <property name="url" value="${db0.url}"/>
       <property name="username" value="${db0.username}"/>
       <property name="password" value="${db0.password}"/>
 </bean>
 
 //数据库1
<bean id="db1" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
       <property name="driverClassName" value="${db1.driverClassName}"/>
       <property name="url" value="${db1.url}"/>
       <property name="username" value="${db1.username}"/>
       <property name="password" value="${db1.password}"/>
 </bean>
 
<bean id="dataSource" class="com.design.pattern.structural.proxy.db.DynamicDataSource">
    <property name="targetDataSources">
       <map key-type="java.lang.String">
          <entry value-ref="db0" key="db0"></entry>
          <entry value-ref="db1" key="db1"></entry>
       </map>
    </property>
    <property name="defaultTargetDataSource" ref="db0"></property>
 </bean>
 <bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
 </bean>

(5) Testing

public class Test {
    public static void main(String[]args){
        Order order = new Order();
        order.setUserId(0);
        /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */
        OrderServiceStaticProxy orderServiceStaticProxy = new OrderServiceStaticProxy();
        orderServiceStaticProxy.saveOrder(order);
    }
}

Test Results:

Test Results

(6) FIG class

FIG case of class

Class Diagram

(7) Best Practices agent

Generally it will require enhanced and afterMethod in part into beforeMethod. To demarcation method

public class OrderServiceStaticProxy {
    /**  在代理类里面注入目标对象 */
    private IOrderService iOrderService;

    /** 我们要在这静态代理类里面增强这个方法 */
    public int saveOrder(Order order){
        beforeMethod(order);
        /** 如果这里有spring容器的话,就不用显示的new了 */
        iOrderService = new OrderServiceImpl();
        int result = iOrderService.saveOrder(order);
        afterMethod();
        return result;
    }

    /** 我们要增强,我们就来写上一个before和after */
    private void beforeMethod(Order order){
        int userId = order.getUserId();
        /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */
        int dbRouter = userId % 2;
        System.out.println("静态代理分配到【db"+dbRouter+"】处理数据");

        //todo 设置dataSource;
        DataSourceContextHolder.setDBType("db"+dbRouter);
        System.out.println("静态代理 before code");
    }

    private void afterMethod(){
        System.out.println("静态代理 after code");
    }
}

6.2 Dynamic Proxy

Project structure

Dynamic proxy class

public class OrderServiceDynamicProxy implements InvocationHandler {

    /** 这是目标类 */
    private Object target;

    /** 通过构造器把目标类注入进来 */
    public OrderServiceDynamicProxy(Object target) {
        this.target = target;
    }

    /** 进行绑定目标对象 */
    public Object bind() {
        Class clazz = target.getClass();
        return Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
    }

    /**
     * proxy:代理类代理的真实代理对象com.sun.proxy.$Proxy0
     * method:我们所要调用某个对象真实的方法的Method对象
     * args:指代代理对象方法传递的参数
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object argObject = args[0];
        beforeMethod(argObject);
        Object object = method.invoke(target, args);
        afterMethod();
        return object;
    }

    public void beforeMethod(Object obj) {
        int userId = 0;
        System.out.println("动态代理before code");
        if (obj instanceof Order) {
            Order order = (Order) obj;
            userId = order.getUserId();
        }
        /** 这里就是实现一个分库的功能,对userId取模2,这里就只会得到0或者是1 */
        int dbRouter = userId % 2;
        System.out.println("动态代理分配到【db"+dbRouter+"】处理数据");
        //todo 设置dataSource;
        DataSourceContextHolder.setDBType(String.valueOf(dbRouter));
    }
    public void afterMethod() {
        System.out.println("动态代理after code");
    }
}

test:

public class Test {
    public static void main(String[]args){
        Order order = new Order();
        order.setUserId(2);
        /** 这里没有采用spring自动注入的方式,而是采用了直接new的方式 */
        IOrderService orderServiceDynamicProxy = (IOrderService) new OrderServiceDynamicProxy(new OrderServiceImpl()).bind();
        orderServiceDynamicProxy.saveOrder(order);
    }
}

Test Results:

Test Results

7. pros and cons

advantage:

  • Audience proxy mode proxy object can be called a real separation
  • Coupling of the system is reduced to some extent, good scalability
  • Protection of the target object
  • Enhanced Audience

Disadvantages:

  • Proxy mode will cause an increase in the number of classes in the system design
  • Add a proxy object on the client and target audience, it will result in slower request processing
  • Increase the complexity of the system

8. Extending -JDK1.7 source code and the frame appearance pattern

8.1 java.lang.reflect.proxy

8.2 org.springframework.aop.framework.ProxyFactoryBean的getObject()

8.3 org.springframework.aop.framework.JdkDynamicAopProxy jdk dynamic proxy encapsulates
org.springframework.aop.framework.CglibAopProxy

8.4 org.apache.ibatis.binding.MapperProxyFactory of newInstance (SqlSession sqlSession) of MapperProxy realized InvocationHandler

MapperProxy

Flyweight used in the process cachedMapperMethod

cachedMapperMethod

Guess you like

Origin www.cnblogs.com/gj-blog/p/10929514.html