赞
踩
假如有一结果api结果返回值的类Person,其在代码中频繁被使用。如果要使用它,一般的方法是:
- public class Main {
- public static void main(String[] args) {
- //方法1,使用全量的构造函数
- Person person1 = new Person("Tom", 28, "Male");
-
- //方法2,使用空的构造函数加setter函数赋值
- Person person2 = new Person();
- person2.setName("Tom");
- person2.setAge(28);
- person2.setGender("Male");
- }
- }
-
- //--》产品
- class Person {
- private String name;
- private int age;
- private String gender;
-
- public Person() {
- }
-
- public Person(String name, int age, String gender) {
- this.name = name;
- this.age = age;
- this.gender = gender;
- }
-
- public void setName(String name) {
- this.name = name;
- }
-
- public void setAge(int age) {
- this.age = age;
- }
-
- public void setGender(String gender) {
- this.gender = gender;
- }
- }
这两种使用方法的弊端有:
(1)方法一:当只需要部分参数的时候需要再定义个构造函数(比如失败的情况只需要code和message,结果肯定是空,因此不需要data),且一旦参数较多,则构造函数冗长;
(2)方法二:setter冗长;
- //使用方法--》指导者
- Person person = Person.builder()
- .name("Tom") //相当于setName("Tom"),只是方法名取name
- .age(28)
- .gender("Male")
- .build();
-
- //--》产品
- public class Person {
- private String name;
- private int age;
- private String gender;
-
- //⑤
- public Person(String name, int age, String gender) {
- this.name = name;
- this.age = age;
- this.gender = gender;
- }
-
- //①
- public static PersonBuilder builder() {
- return new PersonBuilder();
- }
- }
-
- // Java 实现--》建造者
- public class PersonBuilder {
- private String name;
- private int age;
- private String gender;
-
- //②空构造器
- public PersonBuilder() {
- }
-
- //③然后使用setter方法进行设置
- public PersonBuilder name(String name) {
- this.name = name;
- return this; //方法返回当前对象的引用。这样可以支持方法链式调用。
- //通过返回当前对象的引用,可以在一个语句中连续调用对象的方法,而无需每次调用都创建一个新的对象。
- }
-
- public PersonBuilder age(int age) {
- this.age = age;
- return this;
- }
-
- public PersonBuilder gender(String gender) {
- this.gender = gender;
- return this;
- }
-
- //④
- public Person build() {
- return new Person(name, age, gender);
- }
- }
Lombok插件的@Builder注解
- //使用
- Person person = Person.builder()
- .name("Tom")
- .age(28)
- .gender("Male")
- .build();
-
- //lombok优化后
- import lombok.AllArgsConstructor;
- import lombok.Builder;
- import lombok.Data;
- import lombok.NoArgsConstructor;
-
- @Data
- @Builder
- @NoArgsConstructor
- @AllArgsConstructor
- public class Person {
- private String name;
- private int age;
- private String gender;
- }
避免客户端直接访问真实对象,必须通过代理对象访问真实对象。
好处:①在代理对象中限制访问权限(权限校验);②在代理对象中扩展功能(日志记录)
缺点:
- //公共接口
- public interface SmsService {
- String send(String message);
- }
-
- //真实对象
- public class SmsServiceImpl implements SmsService {
- public String send(String message) {
- System.out.println("send message:" + message);
- return message;
- }
- }
-
- //代理对象(自定义 InvocationHandler)
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.InvocationTargetException;
- import java.lang.reflect.Method;
-
- public class DebugInvocationHandler implements InvocationHandler {
- /**
- * 代理类中的真实对象
- */
- private final Object target;
-
- public DebugInvocationHandler(Object target) {
- this.target = target;
- }
-
- public Object invoke(Object proxy, Method method, Object[] args) throws InvocationTargetException, IllegalAccessException {
- //调用方法之前,我们可以添加自己的操作
- System.out.println("before method " + method.getName());
- Object result = method.invoke(target, args);
- //调用方法之后,我们同样可以添加自己的操作
- System.out.println("after method " + method.getName());
- return result;
- }
- }
-
- //代理对象的工厂类
- public class JdkProxyFactory {
- public static Object getProxy(Object target) {
- return Proxy.newProxyInstance( //创建代理对象
- target.getClass().getClassLoader(), // 目标类的类加载
- target.getClass().getInterfaces(), // 代理需要实现的接口,可指定多个
- new DebugInvocationHandler(target) // 代理对象对应的自定义 InvocationHandler
- );
- }
- }
-
- //实际使用
- SmsService smsServiceProxy = (SmsService) JdkProxyFactory.getProxy(new SmsServiceImpl());
- smsServiceProxy.send("java");
-
- //真实对象(类和方法都不能是final的,因为CGLIB代理用到了继承)
- public class SmsService {
- public String send(String message) {
- System.out.println("send message:" + message);
- return message;
- }
- }
-
- //代理对象(自定义 MethodInterceptor)
- public class MethodInterceptor implements MethodInterceptor {
-
- //被代理对象
- private Object target;
-
- public MethodInterceptor(Object target) {
- this.target = target;
- }
-
- public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
- System.out.println("CGLib商店打广告!");
- //调用原来方法
- Object invoke = method.invokeSuper(target, objects);
- System.out.println("CGLib商店做售后!");
- return invoke;
- }
- }
-
- //代理对象的工厂类
- public class CGlibFactoryProxy {
- public Object createProxy(Object target){
- this.target = target;
- //创建代理对象
- Enhancer enhancer = new Enhancer();
- //设置父类,以便 CGLIB 去生成该类的子类
- enhancer.setSuperclass(this.target.getClass());
- //设置方法回调MethodInterceptor实现,你可以认为是设置增强方法
- enhancer.setCallback(new MethodInterceptor());
- //返回代理对象
- return enhancer.create();
- }
- }
-
- //实际使用
- CGlibFactoryProxy factoryProxy = new CGlibFactoryProxy();
- SmsService smsServiceProxy = (SmsService) factoryProxy.createProxy(new SmsService());
- smsServiceProxy.send("java");
Spring 框架的 AOP 使用了动态代理模式来实现切面编程。通过代理,Spring 能够在目标对象的方法执行前、执行后或抛出异常时插入切面逻辑,而不需要修改原始代码。
- (切点)在哪里切入,也就是权限校验等非业务操作在哪些业务代码中执行。
- (处理时机)在什么时候切入,是业务代码执行前还是执行后。
- (处理内容)切入后做什么事,比如做权限校验、日志记录等。
Joint point
:一个方法的执行或者一个异常的处理。
Weaving
:织入,就是通过动态代理,在目标对象方法中执行处理内容的过程。
基于AspectJ实现AOP操作
Spring框架一般都是基于AspectJ实现AOP操作。AspectJ不是Spring组成部分,独立AOP框架,一般把AspectJ和Spring框架一起使用,进行AOP操作。
1.基于xml配置文件实现
2.基于注解方式实现(使用,重要)
//切面类 @Aspect @Component public class UserProxy { //1.相同切入点抽取 @Pointcut(value = "execution(* com.jin.aopanno.User.add(..))") public void pointdemo(){} @Before(value = "pointdemo()") public void before(){ System.out.println("before ..."); } //2.不同切入点抽取 //前置通知(value = 切入点表达式) @Before(value = "execution(* com.jin.aopanno.User.add(..))") public void before(){ System.out.println("before ..."); } //3.自定义注解 @Before("@annotation(com.easychat.annotation.GlobalInterceptor)") public void before(){ System.out.println("before ..."); } private void checkLogin(Boolean checkAdmin) { } } //自定义注解 import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface GlobalInterceptor { //校验登录 boolean checkLogin() default true; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。