使用代理模式进行开发的Spring Boot应用
前言
代理模式是一种结构型设计模式,它允许通过代理对象来控制对真实对象的访问。代理模式可以提供额外的功能,如延迟加载、访问控制、日志记录等。
在Spring Boot开发中,代理模式可以用于控制对对象的访问,并在访问前后添加额外的逻辑。
实现
开发例子
代理模式在权限管理中的应用
假设我们正在开发一个博客系统,系统中有两种用户角色:普通用户和管理员。为了保护敏感数据和功能,我们可以使用代理模式来实现权限管理。
首先,我们创建一个名为BlogService的接口,该接口定义了博客相关的操作方法。然后,我们创建一个名为BlogServiceImpl的真实对象,该对象实现了BlogService接口。最后,我们创建一个名为BlogServiceProxy的代理对象,该对象实现了BlogService接口,并在操作方法中添加权限验证的逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| public interface BlogService { void createBlog(Blog blog); void deleteBlog(long id); }
public class BlogServiceImpl implements BlogService { @Override public void createBlog(Blog blog) { }
@Override public void deleteBlog(long id) { } }
public class BlogServiceProxy implements BlogService { private BlogService blogService; private User currentUser;
public BlogServiceProxy(BlogService blogService, User currentUser) { this.blogService = blogService; this.currentUser = currentUser; }
@Override public void createBlog(Blog blog) { if (currentUser.isAdmin()) { blogService.createBlog(blog); } else { throw new UnauthorizedAccessException("Only admins can create blogs"); } }
@Override public void deleteBlog(long id) { if (currentUser.isAdmin()) { blogService.deleteBlog(id); } else { throw new UnauthorizedAccessException("Only admins can delete blogs"); } } }
|
在使用代理模式的时候,我们可以通过BlogServiceProxy对象来调用博客相关的操作方法,代理对象会在执行前进行权限验证,保护敏感数据和功能。
代理模式在缓存管理中的应用
假设我们正在开发一个电商平台的商品管理模块。在该模块中,我们需要频繁地查询和展示商品信息,为了提高系统性能,我们可以使用代理模式来实现缓存管理。
首先,我们创建一个名为ProductService的接口,该接口定义了商品相关的操作方法。然后,我们创建一个名为ProductServiceImpl的真实对象,该对象实现了ProductService接口。最后,我们创建一个名为ProductServiceProxy的代理对象,该对象实现了ProductService接口,并在操作方法中添加缓存管理的逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public interface ProductService { Product getProduct(long id); }
public class ProductServiceImpl implements ProductService { @Override public Product getProduct(long id) { } }
public class ProductServiceProxy implements ProductService { private ProductService productService; private Map<Long, Product> productCache = new HashMap<>();
public ProductServiceProxy(ProductService productService) { this.productService = productService; }
@Override public Product getProduct(long id) { if (productCache.containsKey(id)) { return productCache.get(id); } else { Product product = productService.getProduct(id); productCache.put(id, product); return product; } } }
|
通过使用代理模式,我们可以在调用商品查询方法时,先从缓存中查找,如果缓存中不存在则调用真实对象的方法并将结果缓存起来,提高系统性能。
使用代理模式控制对敏感资源的访问
在Spring Boot应用中,我们可能需要对某些敏感资源的访问进行控制,例如需要进行身份验证、权限验证等。我们可以使用代理模式来实现这些访问控制。
使用代理模式进行身份验证
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42
| public interface Resource { void access(); }
public class ResourceImpl implements Resource { private String name; public ResourceImpl(String name) { this.name = name; } @Override public void access() { System.out.println("Accessing resource: " + name); } }
public class ProxyResource implements Resource { private Resource resource; private String username; private String password; public ProxyResource(String name, String username, String password) { this.resource = new ResourceImpl(name); this.username = username; this.password = password; } @Override public void access() { if (authenticate(username, password)) { resource.access(); } else { System.out.println("Access denied"); } } private boolean authenticate(String username, String password) { return username.equals("admin") && password.equals("password"); } }
|
在使用时,我们可以创建代理对象,并进行敏感资源的访问。
1 2
| Resource resource = new ProxyResource("Sensitive Resource", "admin", "password"); resource.access();
|
通过以上示例,我们可以看到使用代理模式可以控制对敏感资源的访问,通过代理对象进行身份验证,从而实现访问控制。
使用代理模式进行延迟加载
在某些场景下,我们可能需要延迟加载某些资源,以提高应用的性能和效率。我们可以使用代理模式进行延迟加载。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
| public interface Image { void display(); }
public class RealImage implements Image { private String filename; public RealImage(String filename) { this.filename = filename; loadFromDisk(); } private void loadFromDisk() { System.out.println("Loading image from disk: " + filename); } @Override public void display() { System.out.println("Displaying image: " + filename); } }
public class ProxyImage implements Image { private RealImage realImage; private String filename; public ProxyImage(String filename) { this.filename = filename; } @Override public void display() { if (realImage == null) { realImage = new RealImage(filename); } realImage.display(); } }
|
在使用时,我们可以创建代理对象,并进行延迟加载图片。
1 2 3
| Image image = new ProxyImage("image.jpg"); image.display();
|
通过以上示例,我们可以看到使用代理模式可以实现延迟加载,只有在需要显示图片时才进行实际的加载操作,从而提高了应用的性能和效率。
访问控制
在Spring Boot开发中,我们可能需要对某些对象进行访问控制,以实现权限控制、安全验证等功能。使用代理模式,我们可以在访问对象时进行控制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37
| public interface AccessibleObject { void access(); }
public class AccessibleObjectImpl implements AccessibleObject { @Override public void access() { } }
public class AccessibleObjectProxy implements AccessibleObject { private AccessibleObject object; private String username; public AccessibleObjectProxy(String username) { this.username = username; } @Override public void access() { if (isAdminUser(username)) { if (object == null) { object = new AccessibleObjectImpl(); } object.access(); } else { throw new UnauthorizedAccessException(); } } private boolean isAdminUser(String username) { } }
|
通过代理模式,我们可以使用AccessibleObjectProxy类作为代理对象,并在调用访问方法前进行权限验证和安全控制。
1 2 3
| AccessibleObject object = new AccessibleObjectProxy("admin"); object.access();
|
使用JDK动态代理
JDK动态代理允许我们在运行时为一个接口生成实现类,这对Spring Boot来说非常方便。
比如我们有一个UserService接口:
1 2 3 4 5 6 7
| public interface UserService {
void addUser(User user);
void updateUser(User user);
}
|
然后我们提供一个实现类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Service public class UserServiceImpl implements UserService {
@Override public void addUser(User user) { }
@Override public void updateUser(User user) { }
}
|
现在我们想为这个接口添加一个日志功能,可以使用代理来实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| @Component public class UserServiceProxy implements InvocationHandler {
private UserService target;
public UserServiceProxy(UserService target) { this.target = target; }
@Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { log.info("Calling method: " + method.getName()); Object result = method.invoke(target, args);
log.info("Method result: " + result);
return result; }
}
|
之后我们可以通过代理将日志功能加到服务中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| @Service public class UserServiceImpl implements UserService {
@Override public void addUser(User user) { }
}
@Service public class ProxyFactory {
@Autowired private UserService target;
@Bean public UserService proxy() { return (UserService) Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), new UserServiceProxy(target)); }
}
|
这样每次调用UserService接口方法时,都会附加日志功能。
使用CGLIB动态代理
对于没有实现接口的类,我们可以使用CGLIB动态代理。例如:
1 2 3 4 5 6 7 8
| @Component public class UserDao {
public void save(User user) { }
}
|
同样我们可以为这个类添加通知功能:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Component public class UserDaoProxy implements MethodInterceptor {
@Autowired private UserDao target;
@Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { // log method invocation log.info("Calling method: " + method.getName());
// invoke method Object result = proxy.invoke(target, args);
// log result log.info("Method result: " + result);
return result; }
}
|
创建代理类:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| @Component public class ProxyFactory {
@Autowired private UserDao target;
@Bean public UserDao proxyDao() { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(new UserDaoProxy()); return (UserDao) enhancer.create(); }
}
|
总结
享元模式是一种在Spring Boot开发中非常有用的设计模式,它可以帮助我们减少对象的创建,提高系统的性能和资源利用率。
本篇文章由AI生成