The proxy pattern
Learning from crazy God B station video
Why learn the proxy pattern, because the underlying mechanism of AOP is dynamic proxies!
The proxy mode is divided into static proxy and dynamic proxy. Dynamic proxies do not care who they are in the implementation phase, but specify which objects they are in the run phase. In contrast, the way to write your own proxy class is static proxy.
Static agent
So let’s write a static proxy first
Static agent
Static proxy role analysis
-
Abstract roles: Typically implemented using interfaces or abstract classes
-
Real role: The role being represented
-
Proxy role: Proxy for the real role; After a real role is represented, it usually does some ancillary operations.
-
Customer: Use the agent role to perform some operations.
Code implementation
Rent.java is an abstract role
// Abstract role: rent a house
public interface Rent {
public void rent(a);
}
Copy the code
Host. Java is a real role
// Real character: landlord, landlord wants to rent the house
public class Host implements Rent{
public void rent(a) {
System.out.println("House for Rent"); }}Copy the code
Proxy. Java is the Proxy role
// Proxy role: intermediary
public class Proxy implements Rent {
private Host host;
public Proxy(a) {}public Proxy(Host host) {
this.host = host;
}
/ / rent
public void rent(a){
seeHouse();
host.rent();
fare();
}
/ / the checking
public void seeHouse(a){
System.out.println("Show the tenant a house.");
}
// A broker fee is charged
public void fare(a){
System.out.println("Collect a broker's fee"); }}Copy the code
Client.java is a Client
// Client class, usually customers to find agent!
public class Client {
public static void main(String[] args) {
// The landlord wants to rent a house
Host host = new Host();
// The agent helps the landlord
Proxy proxy = new Proxy(host);
// You go to an agent!proxy.rent(); }}Copy the code
Analysis: in this process, you direct contact is intermediary, just as in real life, you can’t see the landlord, but you still rent to the landlord’s house through the agent, this is the so-called agency model, program is derived from life, so to learn programming, generally more abstract events in the way of looking at life.
Benefits of static proxies:
- Can make our real role more pure. No longer pay attention to some public things.
- The common business is completed by the agent. The division of business is realized.
- Common services become more centralized and convenient when they are extended.
Disadvantages:
- More classes, more proxy classes, the amount of work is larger. Development efficiency is reduced.
We want the benefits of static proxies without the disadvantages, so here we have dynamic proxies!
Static proxies understand again
1, create an abstract role, such as we usually do user business, abstract is to add, delete, change and check!
// Abstract roles: add, delete, change and check services
public interface UserService {
void add(a);
void delete(a);
void update(a);
void query(a);
}
Copy the code
2. We need a real object to do this
// The real object, the person who completed the add, delete, change and check operation
public class UserServiceImpl implements UserService {
public void add(a) {
System.out.println("Added a user.");
}
public void delete(a) {
System.out.println("Deleted a user");
}
public void update(a) {
System.out.println("Updated a user");
}
public void query(a) {
System.out.println("Query a user"); }}Copy the code
Demand comes, now we need to add a log function, how to achieve!
- Idea 1: Add code to the implementation class.
- Idea 2: Using proxies is the best way to do this without changing the business.
4. Set up a proxy class to handle logging! The agent role
// Proxy role, in which to add logging implementation
public class UserServiceProxy implements UserService {
private UserServiceImpl userService;
public void setUserService(UserServiceImpl userService) {
this.userService = userService;
}
public void add(a) {
log("add");
userService.add();
}
public void delete(a) {
log("delete");
userService.delete();
}
public void update(a) {
log("update");
userService.update();
}
public void query(a) {
log("query");
userService.query();
}
public void log(String msg){
System.out.println("Executed."+msg+"Method"); }}Copy the code
5, Test access class:
public class Client {
public static void main(String[] args) {
// Real business
UserServiceImpl userService = new UserServiceImpl();
/ / the proxy class
UserServiceProxy proxy = new UserServiceProxy();
// Use proxy classes to implement logging!proxy.setUserService(userService); proxy.add(); }}Copy the code
OK, now we should have no problem with the proxy model, the key point is that we need to understand the idea;
The core idea in AOP is that we have implemented enhancements to the original functionality without changing the original code
A dynamic proxy
JDK dynamic proxy
A dynamic proxy
-
The role of a dynamic proxy is the same as that of a static proxy.
-
The proxy class for dynamic proxy is dynamically generated. The proxy class for static proxy is written in advance
-
Dynamic proxy can be divided into two types: dynamic proxy based on interface and dynamic proxy based on class
-
- Interface based dynamic proxy —-JDK dynamic proxy
- Class – based dynamic proxy – Cglib
- Javasist is now used to generate dynamic proxies.
package com.company;
public interface Rent {
void rent(a);
}
Copy the code
package com.company;
public class Host implements Rent{
@Override
public void rent(a) {
System.out.println("House for Rent"); }}Copy the code
package com.company;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Proxy2 implements InvocationHandler {
private Rent rent;
public void setRent(Rent rent) {
this.rent = rent;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// This can be enhanced
seeHouse();
// Core: Essence is realized by reflection!
Object result = method.invoke(rent, args);
fare();
return result;
}
// Generate the proxy class, focusing on the second argument, to get the abstract role to proxy! It used to be one role, but now it can represent a class of roles
public Object CreateProxyObj(a) {
return Proxy.newProxyInstance(rent.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
}
/ / the checking
public void seeHouse(a) {
System.out.println("Show the tenant a house.");
}
// A broker fee is charged
public void fare(a) {
System.out.println("Collect a broker's fee"); }}Copy the code
package com.company;
public class Client {
public static void main(String[] args) {
Host host = new Host();
Proxy2 proxy2 = new Proxy2();
proxy2.setRent(host);
Rent rent = (Rent)proxy2.CreateProxyObj(); // Dynamically generate the corresponding proxy class!rent.rent(); }}Copy the code
Deepen the understanding
Let’s implement the proxy using the dynamic proxy we’ll write later UserService!
We could also write a generic dynamic proxy implementation class! Set all proxy objects to Object!
public class ProxyInvocationHandler implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
// Generate the proxy class
public Object getProxy(a){
return Proxy.newProxyInstance(this.getClass().getClassLoader(),
target.getClass().getInterfaces(),this);
}
// proxy: proxy class
// method: the method object of the invocation handler of the proxy class.
public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log(String methodName){
System.out.println("Executed."+methodName+"Method"); }}Copy the code
The test!
public class Test {
public static void main(String[] args) {
// Real objects
UserServiceImpl userService = new UserServiceImpl();
// The invocation handler for the proxy object
ProxyInvocationHandler pih = new ProxyInvocationHandler();
pih.setTarget(userService); // Set the object to be proxied
UserService proxy = (UserService)pih.getProxy(); // Dynamically generate proxy classes!proxy.delete(); }}Copy the code
Test, add, delete, check, check the results!
CGLIB dynamic proxy
Let’s take a look at the code
package proxy;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor
{
Generates a proxy class based on a type. This method is not required to be in the MethodInterceptor
public Object CreatProxyedObj(Class
clazz)
{
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy arg3) throws Throwable
{
// Here is the enhancement
System.out.println("Money");
returnarg3.invokeSuper(arg0, arg2); }}Copy the code
CreatProxyedObj requires only one type clazz to generate a proxy object, so it is a “proxy of class” and creates an object of a new type discovered by printing the type. Unlike JDK dynamic proxies, which require an object to implement an interface (the second of three arguments), Cglib does not require this.
Benefits of dynamic proxies
Static proxy has it, static proxy does not have, it also has!
- Can make our real role more pure. No longer pay attention to some public things.
- The common business is completed by the agent. The division of business is realized.
- Common services become more centralized and convenient when they are extended.
- A dynamic proxy, typically for a certain type of service
- A dynamic proxy can proxy multiple classes, proxy is the interface!