1.问题背景说明以及原因分析2.自定义函数接口
    2.1自定义函数式接口:有参有返回值
    2.2自定义函数式接口:无参无返回值
    2.3自定义函数式接口:有参无返回值
    2.4自定义函数式接口:无参有返回值
3.java中::常用的使用方式
    3.1类名::静态方法名
    3.2对象名::非静态方法名
    3.3类名::new(无参构造)
    3.4类名::new(有参构造)


1.问题背景说明以及原因分析



    问题来源与处理spring security跨域问题的配置信息,好奇

requestMatchers(CorsUtils::isPreFlightRequest)为什么可以这样写.


ResourceServerConfiguration配置信息

@Configuration
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfiguration extends ResourceS
erverConfigurerAdapter {

    @Autowired
    private LoginAuthenticationFilter loginAuthenticationFilter;

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .addFilterBefore(loginAuthenticationFilter, UsernamePasswordAuthenticationFilter.class)
                .csrf().disable().cors()
                .and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED)               .and().authorizeRequests().requestMatchers(CorsUtils::isPreFlightRequest).permitAll()
                .and().authorizeRequests().requestMatchers((httpServletRequest)->CorsUtils.isPreFlightRequest(httpServletRequest)).permitAll()
                .and().requestMatchers().anyRequest()
                .and().anonymous()
                .and().authorizeRequests()
                .antMatchers(
                        "/webjars/**",
                        "/swagger/**",
                        "/captcha.jpg").permitAll()
                .and()
                .authorizeRequests()
                .antMatchers("/**").authenticated();//配置所有访问控制,必须认证过后才可以访问
    }

CorsUtils.javaisPreFlightRequest源码:

public abstract class CorsUtils {
	// 省略部分代码
    public static boolean isPreFlightRequest(HttpServletRequest request) {
        return HttpMethod.OPTIONS.matches(request.getMethod()) && request.getHeader("Origin") != null && request.getHeader("Access-Control-Request-Method") != null;
    }
}

AbstractRequestMatcherRegistryrequestMatchers源码:

public C requestMatchers(RequestMatcher... requestMatchers) {
        Assert.state(!this.anyRequestConfigured, "Can't configure requestMatchers after anyRequest");
        return this.chainRequestMatchers(Arrays.asList(requestMatchers));
    }

RequestMatcher 源码:

public interface RequestMatcher {
    boolean matches(HttpServletRequest var1);

    default RequestMatcher.MatchResult matcher(HttpServletRequest request) {
        boolean match = this.matches(request);
        return new RequestMatcher.MatchResult(match, Collections.emptyMap());
    }

    public static class MatchResult {
        private final boolean match;
        private final Map<String, String> variables;  
}

    AbstractRequestMatcherRegistryrequestMatchers接收的参数为RequestMatcher的可变参数上数组.CorsUtils::isPreFlightRequest中::这种写法是jdk8新特性中的lambda表达式写法,然后去查看RequestMatcher接口,没有标注@FunctionalInterface注解,为什么也能生效?如果你也有这样的疑问请往下看.

    首先想一下什么是函数式接口以及@FunctionalInterface作用

    函数式接口:有且仅有一个抽象方法,但是可以有多个非抽象方法的接口。

    @FunctionalInterface注解作用:用于校验是否符合函数式接口要求.不符合要求会有错误提示.

Java中接口定义的变量是常量吗 java定义接口的意义_自定义


也就是说@FunctionalInterface有或是没有只要符合定义要求都算是函数式接口,这个是之前认知的一个误区.好回到RequestMatcher源码接口中,只有matches一个抽象方法,另外属性的是一个非抽象方法和内部类.完全符合函数式接口定义.所以支持函数式接口写法,下面自己实现几种类型的函数式接口。

2.自定义函数接口



2.1自定义函数式接口:有参有返回值


public interface PersonaInterfaceOne<P,R> {
    // 有参有返回值,P表示参数,R表示返回结果,类似于Java.lang.Function
    R test(P param);
}

jdk8自带function接口

@FunctionalInterface
public interface Function<T, R> {
    R apply(T var1);

    default <V> Function<V, R> compose(Function<? super V, ? extends T> var1) {
        Objects.requireNonNull(var1);
        return (var2) -> {
            return this.apply(var1.apply(var2));
        };
    }

    default <V> Function<T, V> andThen(Function<? super R, ? extends V> var1) {
        Objects.requireNonNull(var1);
        return (var2) -> {
            return var1.apply(this.apply(var2));
        };
    }

    static <T> Function<T, T> identity() {
        return (var0) -> {
            return var0;
        };
    }
}



2.2自定义函数式接口:无参无返回值


public interface PersonaInterfaceTwo {

    // 无参无返回值,类似于:java.lang.Runnable
    void test();

}

jdk8自带Runnable接口

@FunctionalInterface
public interface Runnable {
    void run();
}



2.3自定义函数式接口:有参无返回值


public interface PersonaInterfaceThree<P,A> {
    // 有参无返回值,P为参数1,A为参数2;类似于java.util.function.Consumer,但此接口仅支持一个参数
    void test(P param1,A param2);
}

jdk8自带consumer接口

@FunctionalInterface
public interface Consumer<T> {
    void accept(T var1);

    default Consumer<T> andThen(Consumer<? super T> var1) {
        Objects.requireNonNull(var1);
        return (var2) -> {
            this.accept(var2);
            var1.accept(var2);
        };
    }
}



2.4自定义函数式接口:无参有返回值


public interface PersonaInterfaceFour<R> {
    // 无参有返回值,R为返回值,类似于:java.lang.until。Supplier
    R test();
}

jdk8自带Supplier接口

@FunctionalInterface
public interface Supplier<T> {
    T get();
}



3.java中::常用的使用方式



3.1类名::静态方法名


public class TestPersonalInterface {

    public static String methodOne(int param){
        return "methodOne excute"+param;
    }
    public static void main(String[] args) {
        // 类名::静态方法名
        // 自定义函数式接口
        PersonaInterfaceOne<Integer, String> methodOne = TestPersonalInterface::methodOne;
        String returnMsg = methodOne.test(2);
        System.out.println(returnMsg);  // 输出:methodOne excute2
        // jdk8自带Function实现
//        Function<Integer, String> methodOne = TestPersonalInterface::methodOne;
//        String returnMsg = methodOne.apply(2);
//        System.out.println(returnMsg);
    }
}



3.2对象名::非静态方法名


public class TestPersonalInterface {

    public  String methodTwo(int param){
        return "methodTwo excute"+param;
    }
    
    public static void main(String[] args) {
        // 对象:: 非静态方法名
        // 自定义函数式接口
        PersonaInterfaceOne<Integer, String> methodTwo = new TestPersonalInterface()::methodTwo;
        System.out.println(methodTwo.test(3));  // 输出:methodTwo excute3
         // jdk8自带Function实现
//        Function<Integer, String> methodTwo = new TestPersonalInterface()::methodTwo;
//        System.out.println(methodTwo.apply(3)); // 输出:methodTwo excute3
    }
}



3.3类名::new(无参构造)


public class TestPersonalInterface {

    public TestPersonalInterface() {
        System.out.println("无参构造执行");
    }

    public static void main(String[] args) {
        // 类名:: new
        // 自定义函数式接口
        PersonaInterfaceTwo constructInfo = TestPersonalInterface::new;
        constructInfo.test();  // 输出:无参构造执行
//        Runnable constructInfo = TestPersonalInterface::new;
//        constructInfo.run();  // 输出:无参构造执行
    }
}



3.4类名::new(有参构造)


public class TestPersonalInterface {

    public TestPersonalInterface(String name,Integer age) {
        System.out.println("有参构造执行:"+name+"--"+age);
    }

    public static void main(String[] args) {
        // 有参无返回值
        PersonaInterfaceThree<String,Integer> constructWithArgs = TestPersonalInterface::new;
        constructWithArgs.test("jack",123);  // 输出:有参构造执行:jack--123
    }
}