1.Spring介绍 官网
Spring是一个 IOC(DI) 和 AOP 框架
Spring有很多优良特性
非侵入式:基于Spring开发的应用中的对象可以不依赖于Spring的API
依赖注入:DI(Dependency Injection)是反转控制(IOC)最经典的实现
面向切面编程:Aspect Oriented Programming - AOP
容器:Spring是一个容器,包含并管理应用对象的生命周期
组件化:Spring通过将众多简单的组件配置组合成一个复杂应用。
一站式:Spring提供了一系列框架,解决了应用开发中的众多问题
主要模块
Core(核心):IoC容器、事件、资源、国际化、数据校验、 数据绑定、类型转换、SpEL、AOP 、AOT
Testing(测试):对象模拟、测试框架 、SpringMVC测试、WebTestClient
Data Access(数据访问):事务 、DAO 支持、JDBC、R2DBC、对象关系映射、XML转换
Web Servlet(Servlet式Web):SpringMVC 、WebSocket、SockJS、STOMP 消息
2.Spring-容器 2.1组件和容器 组件:具有一定功能的对象 容器:管理组件(创建、获取、保存、销毁)
2.2IOC和DI
IoC:Inversion of Control(控制反转)
控制:资源的控制权(资源的创建、获取、销毁等)
反转:和传统的方式不一样了
DI:Dependency Injection(依赖注入)
依赖:组件的依赖关系,如 NewsController 依赖 NewsServices
注入:通过setter方法、构造器、等方式自动的注入(赋值)
2.3容器注册 实验一:@Bean-把组件放到容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @SpringBootApplication public class Spring01IocApplication { public static void main (String[] args) { ConfigurableApplicationContext ioc = SpringApplication.run(Spring01IocApplication.class, args); System.out.println("ioc = " + ioc); System.out.println("=============================" ); String[] names = ioc.getBeanDefinitionNames(); for (String name : names) { System.out.println("name = " + name); @Bean("组件名字--默认方法名") public Person person () { Person person = new Person return person; } }
实验二:从容器中获取组件信息
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 @SpringBootApplication public class Spring01IocApplication { public static void test01BeanAnnotation (String[] args) { ConfigurableApplicationContext ioc = SpringApplication.run(Spring01IocApplication.class, args); Object zhangsan = ioc.getBean("zhangsan" ); Person zhangsan = (Person) ioc.getBean("zhangsan" ); System.out.println("对象 = " + zhangsan); Person bean = ioc.getBean(Person.class); System.out.println("bean = " + bean); Map<String, Person> type = ioc.getBeansOfType(Person.class); System.out.println("type = " + type); Person bean = ioc.getBean("zhangsan" , Person.class); System.out.println("bean = " + bean); } }
实验三:容器创建时机及单例特性
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 @SpringBootApplication public class Spring01IocApplication { public static void main (String[] args) { ConfigurableApplicationContext ioc = SpringApplication.run(Spring01IocApplication.class, args); System.out.println("=================ioc容器创建完成===================" ); Dog bean = ioc.getBean(Dog.class); System.out.println("bean = " + bean); Dog bean1 = ioc.getBean(Dog.class); System.out.println("bean1 = " + bean1); Dog bean2 = ioc.getBean(Dog.class); System.out.println("bean2 = " + bean2); } }
运行结果: Dog构造器 ioc容器创建完成 bean = @xxx123 bean1 = @xxx123 bean2 = @xxx123
实验四:@configuration配置类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 @Configuration public class PersonConfig { @Bean("zhangsan") public Person haha () { Person person = new Person (); person.setName("张三2" ); person.setAge(20 ); person.setGender("男" ); return person; } @Bean("zhangsan") public Person zhangsan () { Person person = new Person (); person.setName("张三1" ); person.setAge(20 ); person.setGender("男" ); return person; } @Bean("lisi") public Person lisi () { Person person = new Person (); person.setName("李四" ); person.setAge(20 ); person.setGender("男" ); return person; } }
实验五:@Controller @Service @Repository @Component
这些组件必须在主程序所在的包及其子包结构下: 控制层@Controller 业务层@Service 持久层@Repository 普通组件@Component
实验六:@ComponentScan批量扫描
@ComponentScan(basePackages = “com.atguigu.spring”) 在main方法上
默认扫描主程序所在的包及其子包 如果标注,则只扫描对应包
实验七:@import导入第三方组件
第三方组件想要导入容器中:没办法快速标注分层注解(不能修改源代码)@Bean:自己new,注册给容器 @Component 等分层注解 @Import:快速导入组件 @Import({CoreConstants.class}) 可以在任意位置标注,多个标注只生效一次,因为是单实例的
实验八:@Scope和@Lazy
@Scope 调整组件的作用域:@Scope(“prototype”):非单实例: 容器启动的时候不会创建非单实例组件的对象。 什么时候获取,什么时候创建 @Scope(“singleton”):单实例: 默认值 容器启动的时候会创建单实例组件的对象。 容器启动完成之前就会创建好@Lazy:懒加载 容器启动完成之前不会创建懒加载组件的对象 什么时候获取,什么时候创建 @Scope(“request”):同一个请求单实例 @Scope(“session”):同一次会话单实例
实验九:FactoryBean 利用工厂制作复杂的Bean
不能直接@Bean1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 @Component public class BYDFactory implements FactoryBean <Car> { @Override public Car getObject () throws Exception { System.out.println("BYDFactory 正在制造Car对象..." ); Car car = new Car (); return car; } @Override public Class<?> getObjectType() { return Car.class; } @Override public boolean isSingleton () { return true ; } }
实验十:@Conditional 条件注册
注解可以放在类上和方法上1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 public static void test06 (String[] args) { ConfigurableApplicationContext ioc = SpringApplication.run(Spring01IocApplication.class, args); Map<String, Person> beans = ioc.getBeansOfType(Person.class); System.out.println("beans = " + beans); } public class MacCondition implements Condition { @Override public boolean matches (ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); String property = environment.getProperty("OS" ); return property.contains("mac" ); } } public class WindowsCondition implements Condition { @Override public boolean matches (ConditionContext context, AnnotatedTypeMetadata metadata) { Environment environment = context.getEnvironment(); String property = environment.getProperty("OS" ); return property.contains("Windows" ); } }
派生注解
2.4容器注入 实验一:@Autowired
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 @ToString @Data @Controller public class UserController { @Autowired UserService abc; @Autowired Person bill; @Autowired List<Person> personList; @Autowired Map<String,Person> personMap; @Autowired ApplicationContext applicationContext; }
实验二:@Qualifier和@Primary
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 @Qualifier("bill") @Autowired Person atom;
实验三:@Resource
1 2 3 4 5 6 7 8 9 Autowired是spring规定的, Resource是java规定的,适用于所有组件 @Autowired(required = false) 如果没有找到不报错
实验四:构造器注入和setter注入
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 @ToString @Repository public class UserDao { Dog haha; public UserDao (Dog dog) { System.out.println("UserDao...有参构造器:" +dog); this .haha = dog; } @Autowired public void setDog (@Qualifier("dog02") Dog dog) { System.out.println("setDog..." +dog); this .haha = dog; } }
实验五:xxxAware理解感知接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 @Getter @ToString @Service public class HahaService implements EnvironmentAware , BeanNameAware { private Environment environment; private String myName; @Override public void setEnvironment (Environment environment) { this .environment = environment; } public String getOsType () { return environment.getProperty("OS" ); } @Override public void setBeanName (String name) { this .myName = name; } }
实验六:@Value和@PropertySource
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 @Value("旺财") private String name; @Value("${dog.age}") private Integer age; @Value("${dog.age:Tom}") private Integer age; @Value("#{10*20}") private String color; @Value("#{T(java.util.UUID).randomUUID().toString()}") private String id; @Value("#{'Hello World!'.substring(0, 5)}") private String msg; @Value("#{new String('haha').toUpperCase()}") private String flag; @Value("#{new int[] {1, 2, 3}}") private int [] hahaha; public Dog () { String string = UUID.randomUUID().toString(); System.out.println("Dog构造器..." ); }
实验七:@Profile
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 @Configuration public class DataSourceConfig { @Profile({"dev","default"}) @Bean public MyDataSource dev () { MyDataSource myDataSource = new MyDataSource (); myDataSource.setUrl("jdbc:mysql://localhost:3306/dev" ); myDataSource.setUsername("dev_user" ); myDataSource.setPassword("dev_pwd" ); return myDataSource; } @Profile("test") @Bean public MyDataSource test () { MyDataSource myDataSource = new MyDataSource (); myDataSource.setUrl("jdbc:mysql://localhost:3306/test" ); myDataSource.setUsername("test_user" ); myDataSource.setPassword("test_pwd" ); return myDataSource; } @Profile("prod") @Bean public MyDataSource prod () { MyDataSource myDataSource = new MyDataSource (); myDataSource.setUrl("jdbc:mysql://localhost:3306/prod" ); myDataSource.setUsername("prod_user" ); myDataSource.setPassword("prod_pwd" ); return myDataSource; } }
2.5组件的生命周期 实验一:@Bean指定生命周期初始化和销毁方法
定义Bean组件1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 @Data public class User { private String username; private String password; private Car car; @Autowired public void setCar (Car car) { System.out.println("【User】 ==> setter 自动注入:属性值:" +car); this .car = car; } public User () { System.out.println("【User】 ==> User 构造器..." ); } public void initUser () { System.out.println("【User】 ==> @Bean 初始化:initUser" ); } public void destoryUser () { System.out.println("【User】 ==> @Bean 销毁:destoryUser" ); } }
注入Bean组件1 2 3 4 5 6 7 8 @Configuration public class UserConfig { @Bean(initMethod = "initUser",destroyMethod = "destoryUser") public User user () { return new User (); } }
运行结果 1.构造器 2.自动注入 3.initUser ——————-容器运行中——————- 4.destoryUser
实验二:InitializingBean 和 DisposableBean
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 @Data public class User implements InitializingBean , DisposableBean { private String username; private String password; private Car car; @Autowired public void setCar (Car car) { System.out.println("【User】 ==> setter 自动注入:属性值:" +car); this .car = car; } public User () { System.out.println("【User】 ==> User 构造器..." ); } public void initUser () { System.out.println("【User】 ==> @Bean 初始化:initUser" ); } public void destoryUser () { System.out.println("【User】 ==> @Bean 销毁:destoryUser" ); } @Override public void afterPropertiesSet () throws Exception { System.out.println("【User】 ==> 【InitializingBean】 ==== afterPropertiesSet...." ); } @Override public void destroy () throws Exception { System.out.println("【User】 ==> 【DisposableBean】 ==== destroy...." ); } }
1.构造器 2.自动注入 3.InitializingBean 4.initUser ——————-容器运行中——————- 5.DisposableBean 6.destory销毁
实验三:@PostConstruct 和 @PreDestroy
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 @Data public class User implements InitializingBean , DisposableBean { private String username; private String password; private Car car; @Autowired public void setCar (Car car) { System.out.println("【User】 ==> setter 自动注入:属性值:" +car); this .car = car; } public User () { System.out.println("【User】 ==> User 构造器..." ); } @PostConstruct public void postConstruct () { System.out.println("【User】 ==> @PostConstruct...." ); } @PreDestroy public void preDestroy () { System.out.println("【User】 ==> @PreDestroy...." ); } public void initUser () { System.out.println("【User】 ==> @Bean 初始化:initUser" ); } public void destoryUser () { System.out.println("【User】 ==> @Bean 销毁:destoryUser" ); } @Override public void afterPropertiesSet () throws Exception { System.out.println("【User】 ==> 【InitializingBean】 ==== afterPropertiesSet...." ); } @Override public void destroy () throws Exception { System.out.println("【User】 ==> 【DisposableBean】 ==== destroy...." ); } }
1.构造器 2.自动注入 3.@PostConstruct 4.InitializingBean 5.initUser ——————容器运行中——————- 6.@PreDestroy 7.DisposableBean 8.destory销毁
实验四:BeanPostProcessor --Bean外挂修改器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 @Component public class MyTestBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { System.out.println("【postProcessAfterInitialization】:" +beanName); return bean; } @Override public Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { System.out.println("【postProcessBeforeInitialization】:" +beanName); if (bean instanceof User hello){ hello.setUsername("张三测试" ); } return bean; } }
1.构造器 2.自动注入 3.postProcessBeforeInitialization 4.@PostConstruct 5.InitializingBean 6.initUser 7.postProcessAfterInitialization ——————容器运行中——————- 8.@PreDestroy 9.DisposableBean 10.destory销毁 @Autowired注解是如何实现的?(这里的postProcessBeforeInitialization会在 @Autowired之前) 1.专门有一个处理@Autowired注解的AutowiredAnnotationBeanPostProcessor 2.每个Bean创建以后,会调用BeanPostProcessor的postProcessBeforeInitialization方法 3.postProcessBeforeInitialization里面就会利用反射。得到当前Bean的所有属性,利用反射得到Bean属性上标注的所有注解,看有没有Autowired注解 4.如果有,去容器中找到这个属性对应的组件(按类型,名字)找到。如果没有则报错
3.spring-AOP 3.1日志
场景设计
设计:编写一个计算器接口和实现类,提供加减乘除四则运算
需求:在加减乘除运算的时候需要记录操作日志(运算前参数、运算后结果)
实现:
硬编码与静态代理
定义一个方法接口1 2 3 4 5 6 7 8 9 10 public interface MathCalculator { int add (int i,int j) ; int sub (int i,int j) ; int mul (int i,int j) ; int div (int i,int j) ; }
实现这个接口1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 @Component public class MathCalculatorImpl implements MathCalculator { @Override public int add (int i, int j) { int result = i + j; System.out.println("结果:" +result); return result; } @Override public int sub (int i, int j) { int result = i - j; return result; } @Override public int mul (int i, int j) { int result = i * j; return result; } @Override public int div (int i, int j) { System.out.println("目标方法执行...." ); int result = i / j; return result; } }
测试1 2 3 4 5 6 7 8 9 10 11 12 13 14 @SpringBootTest class Spring02AopApplicationTests { @Autowired MathCalculator mathCalculator; @Test void contextLoads () { int add = mathCalculator.add(1 , 2 ); System.out.println(add); } }
实现静态代理1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 @Data public class CalculatorStaticProxy implements MathCalculator { private MathCalculator target; public CalculatorStaticProxy (MathCalculator mc) { this .target = mc; } @Override public int add (int i, int j) { System.out.println("【日志】add 开始:参数:" +i+"," +j); int result = target.add(i, j); System.out.println("【日志】add 返回:结果:" +result); return result; } @Override public int sub (int i, int j) { int result = target.sub(i,j); return result; } @Override public int mul (int i, int j) { int result = target.mul(i,j); return result; } @Override public int div (int i, int j) { int result = target.div(i,j); return result; } }
测试1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public class MathTest { @Test void test01 () { MathCalculator target = new MathCalculatorImpl (); target.add(1 , 2 ); System.out.println("============" ); MathCalculator proxy = new CalculatorStaticProxy (target); int add = proxy.add(1 , 2 ); System.out.println(add); } }
动态代理
定义一个方法接口1 2 3 4 5 6 7 8 9 10 public interface MathCalculator { int add (int i,int j) ; int sub (int i,int j) ; int mul (int i,int j) ; int div (int i,int j) ; }
实现这个接口1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 @Component public class MathCalculatorImpl implements MathCalculator { @Override public int add (int i, int j) { int result = i + j; System.out.println("结果:" +result); return result; } @Override public int sub (int i, int j) { int result = i - j; return result; } @Override public int mul (int i, int j) { int result = i * j; return result; } @Override public int div (int i, int j) { System.out.println("目标方法执行...." ); int result = i / j; return result; } }
创建日志工具类1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class LogUtils { public static void logStart (String name,Object... args) { System.out.println("【日志】:【" +name+"】开始;参数:" + Arrays.toString(args)); } public static void logEnd (String name) { System.out.println("【日志】:【" +name+"】结束;" ); } public static void logException (String name,Throwable e) { System.out.println("【日志】:【" +name+"】异常;异常信息:" +e.getCause()); } public static void logReturn (String name,Object result) { System.out.println("【日志】:【" +name+"】返回;返回值:" +result); } }
创建动态代理类1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 public class DynamicProxy { public static Object getProxyInstance (Object target) { return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), (proxy, method, args) -> { String name = method.getName(); LogUtils.logStart(name, args); Object result = null ; try { result = method.invoke(target, args); LogUtils.logReturn(name, result); }catch (Exception e){ LogUtils.logException(name, e); }finally { LogUtils.logEnd(name); } return result; } ); } }
测试1 2 3 4 5 6 7 8 9 10 11 12 @Test void test03 () { MathCalculator proxyInstance = (MathCalculator) DynamicProxy.getProxyInstance(new MathCalculatorImpl ()); proxyInstance.add(1 , 2 ); System.out.println("===================================" ); proxyInstance.div(10 ,0 ); }