Spring的兩大特性就是IOC和AOP,
IOC Container,控制反轉容器,通過讀取組態檔或注解,將物件封裝成Bean存入IOC容器待用,程式需要時再從容器中取,實作控制權由程式員向程式的轉變,
一、代碼結構

二、注解掃描
1、新建OrderService、UserService、Test類用于模擬實際開發
@Component("orderService")
@Scope("prototype")
public class OrderService implements BeanNameAware {
@Autowired
private UserService userService;
public void test() {
System.out.println(userService);
}
public void setBeanName(String name) {
this.beanName = beanName;
}
}
@Component("userService")
public class UserService {
}
public class Test {
public static void main(String[] args) {
//對應AnnotationConfigApplicationContext
//掃描 (判斷是否存在Component) + 實體化(Bean的生命周期:1、實體化 2、依賴注入)
CustomApplicationContext customApplicationContext = new CustomApplicationContext(AppConfig.class);
Object userService1 = customApplicationContext.getBean("orderService");
System.out.println(userService);
System.out.println(userService1);
}
}
2、新建注解Component、ComponentScan、Autowired、Scope
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component { // 用于將類注冊成Bean
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan { //用于配置類掃描的包
String value() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD})
public @interface Autowired { //屬性注入
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope { //bean的范圍
String value() default "singleton";
}
3、定義CustomApplicationContext實作注解掃描
- 對應Spring的AnnotationConfigApplicationContext,通過傳入組態檔物件,讀取ComponentScan的Value進行包掃描,掃描后獲取帶@Component注解的類
public class CustomApplicationContext {
private Class configClass;
public CustomApplicationContext(Class configClass) {
this.configClass = configClass;
//掃描(判斷類上是否存在Component)(class檔案) --> 形成beanDefinition
List<Class> classList = scan(configClass);
}
private List<Class> scan(Class configClass) {
List<Class> list = new ArrayList<Class>();
//存在注解,通過value獲取要掃描包路徑
if (configClass.isAnnotationPresent(ComponentScan.class)){
ComponentScan componentScan = (ComponentScan)configClass.getAnnotation(ComponentScan.class);
String path = componentScan.value();
path = path.replace(".","/"); //包轉化為包路徑(com.gg.service)
//掃描path路徑下到類
ClassLoader classLoader = CustomApplicationContext.class.getClassLoader();
// 利用類加載器,根據包路徑獲取URL/target/classes/com/gg/service
URL resource = classLoader.getResource(path);
File file = new File(resource.getFile());
if (file.isDirectory()) {
for (File f: file.listFiles()){
String absolutePath = f.getAbsolutePath(); //類的完整路徑
absolutePath = absolutePath.substring(absolutePath.indexOf("com"),absolutePath.indexOf(".class"));
absolutePath = absolutePath.replace("/",".");
//com.gg.service.userService
Class clazz = null;
try {
clazz = classLoader.loadClass(absolutePath);
// 存在注解,將類加入陣列
if (clazz.isAnnotationPresent(Component.class)) {
list.add(clazz);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
return list;
}
}
4、將掃描獲得的類封裝成beanDefinition
- 掃描得到的類,將beanName、型別、類的范圍封裝成beanDefinition
- getBean時不用重新掃描,直接沖beanDefinitionMap獲取
private Map<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<String, BeanDefinition>();
public CustomApplicationContext(Class configClass) {
this.configClass = configClass;
List<Class> classList = scan(configClass); //掃描得到class
for (Class clazz: classList){
Component component = (Component) clazz.getAnnotation(Component.class);
String beanName = component.value();
BeanDefinition beanDefinition = new BeanDefinition();
if (clazz.isAnnotationPresent(Scope.class)){
Scope scope = (Scope) clazz.getAnnotation(Scope.class);
beanDefinition.setScope(scope.value());
}else{
beanDefinition.setScope("singleton");//默認為單例
}
beanDefinition.setBeanClass(clazz);
beanDefinitionMap.put(beanName,beanDefinition);
}
public class BeanDefinition { //bean的定義
private String scope;
private Class beanClass;
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public Class getBeanClass() {
return beanClass;
}
public void setBeanClass(Class beanClass) {
this.beanClass = beanClass;
}
}
- 至此,我們通過新建CustomApplicationContext,將添加注解的類加入到beanDefinitionMap,
三、實體化Bean
1、單例類先實體化,存入單例池
- 從beanDefinitionMap取出BeanDefinition,對單例類呼叫createBean()實體化,添加到單例池
private Map<String,Object> singletonPool = new ConcurrentHashMap<String, Object>();
public CustomApplicationContext(Class configClass) {
this.configClass = configClass;
//掃描將注解的類存入beanDefinitionMap
List<Class> classList = scan(configClass);
for (Class clazz: classList){
Component component = (Component) clazz.getAnnotation(Component.class);
String beanName = component.value();
BeanDefinition beanDefinition = new BeanDefinition();
if (clazz.isAnnotationPresent(Scope.class)){
Scope scope = (Scope) clazz.getAnnotation(Scope.class);
beanDefinition.setScope(scope.value());
}else{
beanDefinition.setScope("singleton");
}
beanDefinition.setBeanClass(clazz);
beanDefinitionMap.put(beanName,beanDefinition);
}
//將單例類添加到單例池singletonPool
for (String beanName : beanDefinitionMap.keySet()){
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition.getScope().equals("singleton")){
//實體化bean
Object bean = createBean(beanName,beanDefinition);
singletonPool.put(beanName,bean);
}
}
}
private Object createBean(String beanName,BeanDefinition beanDefinition) {
//實體化、填充屬性、Aware、初始化
Class beanClass = beanDefinition.getBeanClass();
try {
// 從beanDefinition中獲取型別,并實體化
Object bean = beanClass.getDeclaredConstructor().newInstance();
//屬性填充
Field[] fields = beanClass.getDeclaredFields(); //DeclaredFields 所有屬性
for(Field field: fields){
if (field.isAnnotationPresent(Autowired.class)){
Object annotationField = getBean(field.getName());
field.setAccessible(true); //反射產生物件要打開權限
field.set(bean,annotationField);
}
}
// Aware
if (bean instanceof BeanNameAware){
((BeanNameAware)bean).setBeanName(beanName); //實作該埠就呼叫此方法
}
// 初始化
if (bean instanceof InitializingBean){
((InitializingBean)bean).afterPropertiesSet(); //實作該埠就呼叫此方法
}
return bean;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
- 新建BeanNameAware、InitializingBean介面,實體類時,通過判斷是否實作該介面,在實體初始化時
public interface BeanNameAware {
public void setBeanName(String name);
}
public interface InitializingBean {
public void afterPropertiesSet();
}
- 通過呼叫createBean()實體化beanDefinition中的類,單例在啟動時實體,原型在呼叫getBean()再實體
2、getBean()
public Object getBean(String beanName){
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition.getScope().equals("prototype")){
return createBean(beanName,beanDefinition);
}else{
Object bean = singletonPool.get(beanName);
if (bean == null){
Object newBean = createBean(beanName,beanDefinition);
singletonPool.put(beanName,newBean);
return newBean;
}
return bean;
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/5040.html
標籤:Java
上一篇:Java基礎
