Spring启动大致流程
@ComponentScan("com.mark")
public class AppConfig {
public static void main(String[] args) {}
@Bean
public User user1() {
return new User();
}
@Bean
public User user2() {
return new User();
}
}
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean("UserService");
userService.test();
- 先去解析AppConfig.class获取到扫描的路径
- 扫描遍历路径下类上存在@Component、@Service等注解.
- 将扫描到的注解存放到一个Map<beanName,Class>中
- 当调用getBean时候会从这个map中拿去
Bean的生命周期,创建过程
- 实例化:将扫描到类,调用构造方法进行实例化.
- 依赖注入:扫描实例化里边的属性如果被@Autowired修饰,进行依赖注入
- 初始化前,判断是否有方法被@PostConstruct修饰,并调用
- 初始中,断是否实现了InitializingBean接口.调用afertPropertisSet()
- 初始化后.判断是否需要进行AOP,进行代理生成,替换原来的bean
实例化
找构造方法
- 当存在无参构造的时候,调用无参构造
- 当没有无参构造的时候
- 只有一个有参 构造,调用有参构造
- 当有多个有参构造的时候,判断是否有@Autowired,有这个注解,调用这个构造,没有注解的话报错
- 当有无参和有参构造,并且有参构造上包含@Autowired时候,调用被注解修饰 的构造方法
@Component
public class CustomerService {
@Autowired
public User user1;
@Autowired
public User user2;
public CustomerService(User user1, User user2) {}
public CustomerService(User user1) {}
}
//会报找不到默认构造方法
==No default constructor found; nested exception is java.lang.NoSuchMethodException
@Component
public class CustomerService {
@Autowired
public User user1;
@Autowired
public User user2;
@Autowired
public CustomerService(User user1, User user2) {}
public CustomerService(User user1) {}
}
当调用构造方法的时候,会根据类型和名字去springMap中查找,并传参.如果没有找到bean会报错
No qualifying bean of type 'com.mark.UserService'
先通过类型去找,如果找到多个bean再通过名字去找.怕万一直接通过名字找,找到的类型不匹配.
依赖注入
遍历类里边的变量,寻找到所有@Autowired
for (Field field : CustomerService.class.getDeclaredFields()) {
if (field.isAnnotationPresent(Autowired.class)) {
System.out.println(field.getName());
field.set(target,map.get(field.getName()));
}
}
我们在AppConfig.class中定义了两个User Bean(@Bean),名字分别user1和user2.在依赖注入的时候也是先通过类型找,如果找到多个再用名字去找.当我们把CustomerService中user1名字改了.
@Autowired
public User user3;
#spring会报错 Unsatisfied dependency expressed through field 'user3'
当我们把AppConfig.class中的一个user bean(@Bean)删除掉,就不会报错了.原因就是因为spring通过类型找到了多个bean,然后才会通过名字去判断对应的bean.如果找到一个就直接返回.
初始化前
在方法中添加@PostConstruce注解,依赖注入之后会被调用.
@Component
public class CustomerService {
@Autowired
public User user3;
@Autowired
public User user2;
public CustomerService(){
System.out.println(111);
}
@PostConstruct
public void test(){
System.out.println(user2);
System.out.println(222);
}
@PostConstruct
public void test1(){
System.out.println(333);
}
}
//结果,user2 有值,说明是再依赖注入之后
111
com.mark.User@311d617d
222
333
初始化
实现 InitializingBean 接口重写 afterPropertiesSet
@Component
public class CustomerService implements InitializingBean {
@Autowired
public User user3;
@Autowired
public User user2;
public CustomerService(){
System.out.println(111);
}
@PostConstruct
public void test(){
System.out.println(user2);
System.out.println(222);
}
@PostConstruct
public void test1(){
System.out.println(333);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(444);
}
}
//结果
111
com.mark.User@ed17bee
222
333
444
判断是否实现了 InitializingBean
CustomerService customerService = new CustomerService();
if(customerService instanceof InitializingBean){
(InitializingBean)customerService.afterPropertiesSet();
}
初始化后(AOP)
在AppConfig上添加注解@EnableAspectJAutoProxy
添加切面
@Component
@Aspect
public class CustomerPointcut {
/**
* 定义切点
*/
@Pointcut("execution(public void com.mark.CustomerService.test())")
public void pointCut(){}
/**
* 织入
* @param joinPoint
*/
@Before("pointCut()")
public void before(JoinPoint joinPoint) {
System.out.println("代理类执行前");
}
}
CustomerService customerService = context.getBean(CustomerService.class);
System.out.println(customerService.getClass());
customerService.test();
打印出来的是CustomerService$EnhancerBySpringCGLIB$c557704a代理对象.
大致执行流程是
proxy.test() ->intercept() ->执行前->target.test() ->执行后
代理类中user变量是没有值的.在target中才会有值.
==
修改切点
/**
* 定义切点
*/
@Pointcut("execution(public void com.mark.CustomerService.test*())")
public void pointCut(){}
在test方法中调用test1()
@Component
public class CustomerService {
@Autowired
private User user;
public void test(){
System.out.println("这是test");
test1();
}
public void test1(){
System.out.println("这是test1");
}
}
#执行结果===
#代理类执行前
#这是test
#这是test1
这时候test1()并没有走代理逻辑.只有test()方法走了.
修改方法,自己注入自己.然后再调用,就可以了
@Component
public class CustomerService {
@Autowired
private User user;
@Autowired
private CustomerService customerService;
public void test(){
System.out.println("这是test");
customerService.test1();
}
public void test1(){
System.out.println("这是test1");
}
}
#结果=====
#代理类执行前
#这是test
#代理类执行前
#这是test1
本文暂时没有评论,来添加一个吧(●'◡'●)