在上一个博客中《模拟Spring IoC(一)Component及Autowired注解》中介绍了两个注解,Component注解和Autowired注解,下来就解释一下Bean注解。
Bean注解产生原因:
Autowired注解的缺陷:Autowired只能获取池子中的对象,而池中对象都是需要给对应的类以@Component注解;对于不可更改的Jar包中的类,就没有办法增加@Component注解,也就不能实现“注入”操作。Bean注解就是为了解决这样的问题存在的。
Bean注解:
@Retention(RUNTIME)
@Target(METHOD)
public @interface Bean {
}
Bean注解的使用场景
场景一:
当我么需要注入的对象是一个不可更改的类时,需要使用Bean注解。比如,jar包中的类,众所周知,jar包中的类不能被更改,这就意味着不能给类增加Component注解,也就无法将该类以及成员装入容器中。而Bean注解就可以很好的解决这一点。
解决办法:创建一个配置类Config,在类中生成一个方法例如getComplex(),将该需要注入的类(类似jar包中的)作为方法返回值类型。给方法增加Bean注解,将这个方法的返回值对象和返回值对象类型封装到beanDefinition,以返回值类型名为键,beanDefinition对象为值存储到池子(map)中!(将Complex类和c对象存储到beanPool),如此就将jar包中类装入到了容器中。
下面Complex类,是自己编写的,导成了一个jar包
@Component
public class Config {
@Bean
public Complex getComplex() {
System.out.println("将Complex这个不能更改的类,装入池子!");
Complex c = new Complex(1.0, -3.0);
c.setReal(c.getReal() + 2);
return c;
}
}
看一下Bean注解的方法的处理过程
private static void dealBean(Object object,Class<?> klass) {
Method[] methods = klass.getDeclaredMethods();
for(Method method:methods) {
//没有Bean注解的方法跳过
if(!method.isAnnotationPresent(Bean.class)) {
continue;
}
if(method.getParameterCount() >0) {
//TODO有参数的稍后再处理
continue;
}
//处理无参数的bean注解
Class<?> returnType = method.getReturnType();//获取返回值类型
try {
Object beanObject = method.invoke(object);//通过执行方法获取返回值
//将方法的返回值类型及返回值装入beanPool
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setKlass(returnType);
beanDefinition.setObject(beanObject);
beanDefinition.setSingleton(true);
beanDefinition.setInject(false);
beanPool.put(returnType.getName(), beanDefinition);
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
场景二:
若相关类没有提供可用的构造方法;所谓的没有提供可用的构造方法包括相关构造方法是private的,或者,构造方法不能直接调用,或者,构造方法不能直接生成对象!在这种情况下,由于对于Component注解的处理是通过调用相关类的无参构造产生的,那么,对于上述情况,就不能产生这个类的对象!
此时,可以通过Bean注解,调用合适的获取该类对象的方法,取得这个类的对象,并加入BeanPool中!
下面以Calendar类为例,该类就是典型的构造方法是protected的,不能直接调用,需要使用getgetInstance()
创建实例
public class Config {
@Bean
public Calendar getDate() {
Calendar date = Calendar.getInstance();
return date;
}
}
场景三:
相关类的对象,不是简单无参构造就能直接使用的;意思是:这个类虽然存在无参构造,但是,无参构造出来的对象不能直接使用。那么,在这种情况下,通过Bean注解的方法,完成其对象所必须的基础数据,从而使得该对象可用!
以数据库配置为例,connection对象就是一个很典型的,不能通过直接调用无参构造生成一个对象就可以正常使用的例子
@Component
public class Config {
@Bean
public Connection getConnection() {
Connection connection = null;
try {
Class.forName("com.mysql.jdbc.Driver");
connection = DriverManager.getConnection(
"jdbc:mysql://localhost:3306/test?useSSL=false",
"root",
"123456");
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (SQLException e) {
e.printStackTrace();
}
return connection;
}
}
上述三种场景均为Autowired注解无法处理的,只能由Bean注解处理的情况。但是,Bean注解却不仅仅只能用于这三种场景,Autowired注解可以实现的功能Bean注解也同样可以,这意味着Bean注解也可以用在普通类上。
比如TwoClass一个普通类,将之放入Config类中,也能实现与Autowired相同的功能
@Component
public class Config {
@Bean
public TwoClass getTwoClass() {
TwoClass two = new TwoClass();
return two;
}
}
在上面列举了几种Bean注解的使用场景,而这些方法都只是无参的,但仍有一些有参的方法也需要Bean注解,关于有参数的方法处理会在之后的博文中说明。
全部代码请跳转–>GitHub https://github.com/Arrvine/mspring-IoC