@lazy注解處理循環注入問題


 
        

@Service
public class A extends GenericBaseService {
@Autowired
private B b;
}
@Service
public class B extends GenericBaseService {
@Autowired
private A a;
}

 
        

spring中的bean和java對象的區別:
假如有個類Student,對於java對象 Student st=new Student();
但對於bean: 創建出java對象后還要經過一系列的處理器處理,如是否需要動態代理,是否需要注入各種屬性

 
        

spring底層是支持循環依賴的,A依賴B B依賴A,這里說的A和B都是spring bean;
如果把bean的創建過程簡述為2個步驟的話: 1. 創建 一個對象(底層通過反射) 2. 給對象注入屬性,那么A和B的創建流程如下
1. A的創建: A a=new A();
2. 屬性注入:發現需要B
3. 創建B b=new B();
4. 屬性注入: 發現需要A,此時A已經創建了.只是還沒經過各種后置處理器處理,所以B是可以完成屬性注入的,只是一個半成品
5.之后回到第2步,就可以給A賦值了,循環依賴到此解決

 
        

//然而生產中的情況復雜多,相互依賴的關系網太復雜了,所以經常還是會出現提示循環依賴的異常,此時可以用另外一個方式去解決,那就是@Lazy注解了

 
        

@Service
public class A extends GenericBaseService {
@Autowired
@Lazy
private B b;
}

 
        

加了lazy的原理如下:
1. A的創建: A a=new A();
2. 屬性注入:發現需要B,查詢字段b的所有注解,發現有@lazy注解,那么就不直接創建B了,而是使用動態代理創建一個代理類B
3. 此時A跟B就不是相互依賴了,變成了A依賴一個代理類B1,B依賴A

 
        

驗證這個方式很簡單:
從容器中分別獲取A a 和B b 的實例對象,然后從A中獲取它依賴的對象b1,打印b1的class對象,判斷b1是否和b相等

 //下面使用Student和School類來測試
@Component
public class School {
	@Autowired
	@Lazy
	private Student student;

	public Student getStudent() {
		return student;
	}

	public void setStudent(Student student) {
		this.student = student;
	}
}
@Component
public class Student {

	@Autowired
	private School school;

	public School getSchool() {
		return school;
	}

	public void setSchool(School school) {
		this.school = school;
	}
}
public class APP {
	public static void main(String[] args) throws InterruptedException {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(Configurate.class);
		School school =(School) applicationContext.getBean("school");
		Student student =(Student) applicationContext.getBean("student");
		System.out.println(school.getClass());//class com.aop.School
		System.out.println(student.getClass());//class com.aop.Student
		System.out.println(school.getStudent()==student);//false
		System.out.println(school.getStudent().getClass());//class com.aop.Student$$EnhancerBySpringCGLIB$$834812b7


	}

}

 

 底層源碼:

 

 

 

 跟到后面可以看到創建了cglib動態代理:

 

 

  





免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM