使用注解的方式来加载bean
http://blog.youkuaiyun.com/github_26672553/article/details/78214223
前面我们已经了解了IoC容器
的概念,并且写了一个登录验证的案列,来演示了在Spring 框架中如何配置一个xml文件,然后加载这个文件,实现对登录验证条件的灵活设置。
xml文件主要包含各种<bean>
,并且还可以设置<bean>
之间的依赖关系。
我们现在学习一下:使用注解的方式加载bean
文档地址:
https://docs.spring.io/spring/docs/5.0.1.BUILD-SNAPSHOT/spring-framework-reference/core.html#beans-annotation-config
1、创建一个java类MyConfig.java
,代码如下:
package SpringLean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration // 表明这是一个配置类
public class MyConfig {
/**
* 用户登录验证配置方法
* @return 返回这个验证条件配置对象
*/
@Bean
public UserValidateConfig userValidateConfig1(){
// 设置好验证条件:用户名长度8、QQ必填
UserValidateConfig userValidateConfig = new UserValidateConfig(){
{
setUserNameLength(8);
setQQRequired(true);
}
};
return userValidateConfig;
}
/**
* 用户服务方法
* @return 返回一个UserService类的对象
*/
@Bean
public UserService myUserService(){
// 实例化UserService类对象
UserService userService = new UserService();
// 给用户服务类设置验证条件
userService.setUserValidateConfig(this.userValidateConfig1());
return userService;
}
}
这个类中有2个方法myUserService()
,该方法中添加上用户登录的验证条件,这个方法相当于是提供给了外部的一个接口,外部会调用这个方法来获取UserService对象
(这个过程就是加载Bean)。
我们可以给UserService
设置this.userValidateConfig1()
,那么也就可以设置this.x()
,只要这个x()
方法里处理好验证条件的具体就行,这样也达到了灵活的用户登录验证条件配置。
2、然后我们来到入口函数,看看如何加载到MyConfig
这个类
public static void main(String[] args) throws Exception{
// 之前加载xml的方式
//ApplicationContext context = new ClassPathXmlApplicationContext("userConfig.xml");
ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
// 从配置文件中设置好了相关验证
UserService userService = (UserService)context.getBean("myUserService");
userService.userLogin("zhangSan","111111111");
}
了解java的反射
先简单理解下:比如我们执行User user = new User();
,然后各种方法调用。
这个整个过程执行了下面这些步骤:
1、编译(.class文件),JVM启动
2、JVM的类加载器 加载类的Class对象
3、为你的类分配内存(这一步就是 new User()的过程)
4、各种执行,,,程序执行完成就结束了
这些都依赖于你写了new User()
后,JVM自动帮你加载和分配内存的前提下。
反射就在于你没有new
,但你就是需要在运行的过程中(简称运行时)调用到某个类(这叫动态加载)。
在下面的代码,创建一个Test类
,传统的我们要使用这个类,是这样:
// 实例化
Test test1 = new Test();
// 调用方法
test1.showName("jack");
现在我们利用反射机制:
// 获取到Test类
Class myClass = Class.forName("SpringLean.Test");
// 获取类中的方法
Method showName = myClass.getDeclaredMethod("showName", String.class);
// 实例化Test类
Object test = myClass.newInstance();
String name = "jack";
showName.invoke(test,name); // 调用Test类中的方法
注解是什么?
java 5后开始支持。至于xml和注解哪个好?这个没有标准答案。
1、我们先来创建一个自定义注解
public @interface NameCheck{
String forbidden();
}
注意是@interface,很类似interface,可暂且理解为一个特殊的Java接口
2、注解有什么用?来看我们测试类
public class Test {
@xxxx //打上一个注解,可以实现某种功能:比如过滤特殊的name
public void showName(String name){
System.out.println(name);
}
}
我们现在需要一个注解,在showName()
方法的时候实现参数过滤功能。
3、完成我们的自定义注解
package MyAnnos;
import javax.xml.bind.Element;
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 NameCheck {
String forbidden() default "jack,zhangSan";
}
我们这个自定义的注解,是要作用域类中的方法上,NameCheck
有2个默认值。
第二步我们已经创建了一个Test类
,我们要来看看,在这个类中的方法里如何使用到注解NameCheck
:
@NameCheck
public void showName(String name){
System.out.println(name);
}
这样就表示给showName()
方法打上了注解。
4、来到入口函数,我们要验证一下注解有没有发挥作用。
上面我们已经了解了java的反射机制
,并且通过反射机制,我们可以拿到Test类
中的方法。
// 获取到Test类
Class myClass = Class.forName("SpringLean.Test");
// 获取类中的方法
Method showName = myClass.getDeclaredMethod("showName", String.class);
// 实例化Test类
Object test = myClass.newInstance();
String name = "jack";
// 获取方法上的注解
if (showName.isAnnotationPresent(NameCheck.class)){
NameCheck nameCheck = showName.getAnnotation(NameCheck.class);
if (nameCheck.forbidden().contains(name)){
System.out.println("有非法字符串");
}else{
System.out.println("通过");
}
}
我们判断这个方法是否存在一个NameCheck
的注解,然后把我们的定义的一个字符串传递给nameCheck.forbidden()
,果然NameCheck
中默认就有这个字符串。
最后我们的程序会打印:
有非法字符串
至此,注解我们就有了一个基本的了解。有点儿复杂,我们应该知道内部需要用到Java的反射机制。