# spring **Repository Path**: luzhizero/spring ## Basic Information - **Project Name**: spring - **Description**: 整理了spring的aop,ioc等功能 - **Primary Language**: Java - **License**: Not specified - **Default Branch**: master - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 0 - **Created**: 2020-01-10 - **Last Updated**: 2020-12-19 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # spring spring中常用jar包: Spring AOP:Spring的面向切面编程,提供AOP(面向切面编程)的实现 Spring Aspects:Spring提供的对AspectJ框架的整合 Spring Beans:Spring IOC的基础实现,包含访问配置文件、创建和管理bean等。 Spring Context:在基础IOC功能上提供扩展服务。 Spring Context Support:Spring context的扩展支持,用于MVC方面。 Spring Core:Spring的核心工具包 Spring expression:Spring表达式语言 Spring Instrument:Spring对服务器的代理接口 Spring Instrument Tomcat:Spring对tomcat连接池的集成 Spring JDBC:对JDBC的简单封装 Spring JMS:为简化jms api的使用而做的简单封装 Spring orm:整合第三方的orm实现,如hibernate,ibatis,jdo以及spring 的jpa实现 Spring oxm:Spring对于object/xml映射的支持,可以让JAVA与XML之间来回切换 Spring test:对JUNIT等测试框架的简单封装 Spring tx:为JDBC、Hibernate、JDO、JPA等提供的一致的声明式和编程式事务管理。 Spring web:包含Web应用开发时,用到Spring框架时所需的核心类,包括自动载入WebApplicationContext特性的类、Struts与JSF集成类、文件上传的支持类、Filter类和大量工具辅助类。 Spring webmvc:包含SpringMVC框架相关的所有类 idea创建spring项目 1.创建maven的项目后再pom中引入 ``` org.springframework spring-context 5.1.6.RELEASE ``` 2.创建项目格式 ![输入图片说明](https://images.gitee.com/uploads/images/2020/0110/105414_d6fbf5a8_5496301.png "屏幕截图.png") 3.右击resouces文件夹,创建applicationContext.xml配置文件 ![输入图片说明](https://images.gitee.com/uploads/images/2020/0110/105451_a006ab69_5496301.png "屏幕截图.png") 4.创建结果如下 ``` ``` 关于控制反转 控制反转 IOC(Inverse Of Control)是Spring核心功能之一,“控制反转”(IOC) 将应用程序的配置和依赖性规范与实际的应用程序代码分开。 创建bean的方式 1.配置文件创建 1.1 ``` ``` 1.2 但是有些特殊情况,对象并不是通过new 来进行创建,而是通过对象工厂的方式来创建,spring的配置文件也支持这种方式创建bean.我们在定义bean标签时需要,需要把的class属性配置为工厂类(或者把factory-bean属性配置为工厂类对象),使用属性factoryMethod来定义工厂类中获取此对象的方法。 创建一个dao,并为它写一个简单的工厂 ``` public class MyDao { public MyDao() { System.out.println("mydao被创建"); } } ``` ``` public static MyDao getDao(){ System.out.println("DaoFactory的getdao方法被调用"); return new MyDao(); } ``` ``` ``` 这里值得一提的是,工厂类方法必须是静态方法,如果方法不为静态的情况下,就以如下方式进行创建 ``` ``` 1.3 spring的bean默认情况下都是单例的,如果需要创建非单例的项,则在bean标签中添加scope="prototype"来进行修改(4.0以前为singleton=”false”) 2.注解创建对象 常用注解: @Component 该注解需要定义在类上,表示该类对象需要通过Spring来创建。 @Controller 该注解需要定义在控制层的类上,表示该类对象需要通过Spring来创建,@Controller层是spring mvc的注解,具有将请求进行转发,重定向的功能。 @Service 该注解需要定义在业务层的类上,表示该类对象需要通过Spring来创建,这个注解只是标注该类处于业务逻辑层。 @Repository 该注解需要定义在数据层的类上,表示该类对象需要通过Spring来创建,还注解还具有将数据库操作抛出的原生异常翻译转化为spring的持久层异常的功能。 上述4个注解的作用等同于标签,在使用这些注解时可以传入一个字符串作为bean id,如果没有传入bean id则默认bean id等于类名首字母小写。 3.通过@Configuration和@Bean的组合注解来进行对象的创建 ``` @Configuration public class ServiceConfigration { @Bean(value = "myService") public MyServiceImpl getMyServiceImpl(){ return new MyServiceImpl("张三"); } } ``` 注意:上述使用注解的方式进行bean创建时,需要在applicationContext.xml中声明添加了注解的这些类所在的包名,这样Spring才能去扫描这些包,如果不配置注解将不生效。配置方式如下: ``` ``` 属性注入到bean中 1.property标签进行注入,name表示注入哪一个属性,ref为备注如的bean的id ``` ``` 这种方式还支持list,set和map注入,这里就不展开讲了. 2.@Autowired和@Resource 上述两个注解用于进行依赖注入,只不过@Autowired按属性类型自动注入,而@Resource默认按属性名称自动注入。@Resource有两个属性是比较重要的,分是name和type,Spring将@Resource注解的name属性作为bean id去容器中查找,而type属性则解析为bean的类型。所以如果使用name属性,则优先通过属性名称自动注入,而使用type属性时则使用类型匹配自动注入策略。如果既不指定name也不指定type属性,这时将通过优先用过属性名称自动注入策略。无论使用@Resource还是@AutoWired如果匹配策略是按照类型匹配,这时Spring容器中有超过1个相同类型对象时,就会出现异常。 3.构造函数注入 当我们创建bean时希望在里面的属性添加值得时候可以在bean标签内部添加标签来注入属性值,类必须给与对应的构造函数.多个属性需要多个标签,并且顺序与类相同. ``` 张三 ``` springbean的生命周期 ![输入图片说明](https://images.gitee.com/uploads/images/2020/0110/145417_4e26b768_5496301.png "屏幕截图.png") 各种接口方法分类 Bean的完整生命周期经历了各种方法调用,这些方法可以划分为以下几类: Bean自身的方法: 这个包括了Bean本身调用的方法和通过配置文件中的init-method和destroy-method指定的方法 Bean级生命周期接口方法: 这个包括了BeanNameAware、BeanFactoryAware、InitializingBean和DiposableBean这些接口的方法 容器级生命周期接口方法: 这个包括了InstantiationAwareBeanPostProcessor 和BeanPostProcessor 这两个接口实现,一般称它们的实现类为“后处理器”。 工厂后处理器接口方法: 这个包括了AspectJWeavingEnabler, ConfigurationClassPostProcessor, CustomAutowireConfigurer等等非常有用的工厂后处理器接口的方法。工厂后处理器也是容器级的。在应用上下文装配配置文件之后立即调用。 一、创建和属性注入 1.Bean的创建,由BeanFactory读取Bean定义文件,并生成各个实例 2.Setter注入,执行Bean的属性依赖注入 二、将容器和bean本身的信息暴露出来便于使用 3.BeanNameAware的setBeanName(), 如果实现该接口,则执行其setBeanName方法 4.BeanFactoryAware的setBeanFactory(),如果实现该接口,则执行其setBeanFactory方法 4.ApplicationContext的setApplicationContext(),如果实现该接口,则执行其setApplicationContext方法 三、初始化过程 5.BeanPostProcessor接口下的postProcessProperties(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processBeforeInitialization()方法 6.InitializingBean的afterPropertiesSet(),如果实现了该接口,则执行其afterPropertiesSet()方法 7.Bean定义文件中定义init-method 8.BeanPostProcessor接口的processAfterInitialization(),如果有关联的processor,则在Bean初始化之前都会执行这个实例的processAfterInitialization()方法 四、销毁过程 9.DisposableBean的destroy(),在容器关闭时,如果Bean类实现了该接口,则执行它的destroy()方法 10.Bean定义文件中定义destroy-method,在容器关闭时,可以在Bean定义文件中使用“destory-method”定义的方法 下面以User类来进行bean的创建 ``` @Component public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor { @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { System.out.println("BeanFactoryPostProcessor调用postProcessBeanFactory方法"); } public MyBeanFactoryPostProcessor() { super(); System.out.println("MyBeanFactoryPostProcessor的构造方法被调用"); } } ``` ``` @Component public class MyBeanPostProcessor implements BeanPostProcessor { public MyBeanPostProcessor() { super(); System.out.println("这是BeanPostProcessor实现类构造器!!"); // TODO Auto-generated constructor stub } //这两个方法的第一个参数都是要处理的Bean对象,第二个参数都是Bean的name。返回值也都是要处理的Bean对象。这里要注意。 @Override public Object postProcessAfterInitialization(Object arg0, String arg1)throws BeansException { System.out.println("BeanPostProcessor接口方法postProcessAfterInitialization对属性进行更改!"); return arg0; } @Override public Object postProcessBeforeInitialization(Object arg0, String arg1) throws BeansException { System.out.println("BeanPostProcessor接口方法postProcessBeforeInitialization对属性进行更改!"); return arg0; } } ``` ``` @Component public class MyInstantiationAwareBeanPostProcessor extends InstantiationAwareBeanPostProcessorAdapter { public MyInstantiationAwareBeanPostProcessor() { super(); System.out.println("这是InstantiationAwareBeanPostProcessorAdapter实现类构造器!!"); } // 接口方法、实例化Bean之前调用 @Override public Object postProcessBeforeInstantiation(Class beanClass, String beanName) throws BeansException { System.out.println("InstantiationAwareBeanPostProcessor调用postProcessBeforeInstantiation方法"); return null; } // 接口方法、实例化Bean之后调用 @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("InstantiationAwareBeanPostProcessor调用postProcessAfterInitialization方法"); return bean; } // 接口方法、设置某个属性时调用 @Override public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException { System.out.println("InstantiationAwareBeanPostProcessor调用postProcessProperties方法"); return super.postProcessProperties(pvs, bean, beanName); } } ``` ``` package com.lzlearn.model; import org.springframework.beans.BeansException; import org.springframework.beans.factory.*; public class User implements BeanFactoryAware, BeanNameAware,InitializingBean, DisposableBean { private String name; private String sex; public String getName() { return name; } public void setName(String name) { System.out.println("【注入属性】注入属性name"); this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { System.out.println("【注入属性】注入属性sex"); this.sex = sex; } public User(String name, String sex) { System.out.println("User的全参构造被调用"); this.name = name; this.sex = sex; } @Override public String toString() { return "User{" + "name='" + name + '\'' + ", sex='" + sex + '\'' + '}'; } public User() { System.out.println("User的无参构造被调用"); } private BeanFactory beanFactory; private String beanName; @Override public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("【BeanFactoryAware接口】调用BeanFactoryAware.setBeanFactory()"); this.beanFactory = beanFactory; } @Override public void setBeanName(String s) { System.out.println("【BeanNameAware接口】调用BeanNameAware.setBeanName()"); this.beanName = s; } @Override public void afterPropertiesSet() throws Exception { System.out.println("【InitializingBean接口】调用InitializingBean.afterPropertiesSet()"); } // 通过的init-method属性指定的初始化方法 public void myInit() { System.out.println("【init-method】调用的init-method属性指定的初始化方法"); } @Override public void destroy() throws Exception { System.out.println("【DiposibleBean接口】调用DiposibleBean.destory()"); } // 通过的destroy-method属性指定的初始化方法 public void myDestory() { System.out.println("【destroy-method】调用的destroy-method属性指定的初始化方法"); } } ``` ``` package com.lzlearn.test; import com.lzlearn.model.User; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringTest { public static void main(String[] args) { System.out.println("现在开始初始化容器"); //读取配置文件 ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); System.out.println("容器初始化成功"); //获取User的bean User user = classPathXmlApplicationContext.getBean("user", User.class); System.out.println(user); System.out.println("开始销毁bean容器"); ((ClassPathXmlApplicationContext)classPathXmlApplicationContext).registerShutdownHook(); } } ``` ``` ``` 测试结果如下 ![输入图片说明](https://images.gitee.com/uploads/images/2020/0110/150226_25a1ada2_5496301.png "屏幕截图.png") 关于AOP 在使用AOP时,需要了解动态代理,(JDK和CGlib)动态代理模式 AOP(Aspect Oriented Programming),即面向切面编程。AOP是对OOP(Object Oriented Programming,面向对象编程)的补充和完善。 OOP允许开发者定义纵向的关系,但并不适合定义横向的关系,例如日志功能。日志代码往往横向地散布在所有对象层次中,而与它对应的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理、事务管理等等,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。 AOP技术恰恰相反,它利用一种称为"横切"的技术,剖解开封装的对象内部,并将那些影响了多个类的公共行为封装到一个可重用模块,并将其命名为"Aspect",即切面。所谓"切面",简单说就是那些与业务无关,却为业务模块所共同调用的逻辑或责任封装起来,便于减少系统的重复代码,降低模块之间的耦合度,并有利于未来的可操作性和可维护性。 AOP核心概念: JointPoint(连接点): 表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等等,它自身还可以嵌套其它 JointPoint。连接点代表了时间,也就是何时去执行 Pointcut(切入点): 表示一组 JointPointt,是在程序中用表达式、正则对连接点的描述。 Execution (* com.woniu.service.*.*(..)) Advice(通知): 所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。通知代表的所做的事情 Aspect(切面): Aspect声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。切面就是对何时做什么事情的抽象。 目标对象 代理的目标对象 织入(weave) 将切面应用到目标对象并导致代理对象创建的过程 AOP有两种实现方式,分别为原生实现以及整合Aspect实现 首先创建拦截器来进行增强操作,除了前置和后置,也可以进行环绕增强 ``` public class TranscationAdvice implements MethodBeforeAdvice , AfterReturningAdvice { @Override public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable { //后置处理器 System.out.println("提供后置操作,如提交事务"); } @Override public void before(Method method, Object[] objects, Object o) throws Throwable { //前置处理器 System.out.println("提供前置操作,如开启事务"); } } ``` 创建一个MyService的接口以及其实现类MyServiceImpl 在xml中进行配置 ``` ``` 调用 ``` //读取配置文件 ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); MyService myService = classPathXmlApplicationContext.getBean("proxy", MyService.class); User user = myService.selectUser(); System.out.println(user); ``` 执行结果 ![输入图片说明](https://images.gitee.com/uploads/images/2020/0110/154521_bbb8f6f1_5496301.png "屏幕截图.png") AOP整合Aspect框架实现AOP(注解版) 引入pom ``` org.aspectj aspectjrt 1.9.2 org.aspectj aspectjweaver 1.9.2 ``` 创建拦截器类,并交给spring托管 ``` package com.lzlearn.config; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Component; @Component @Aspect public class TranscationConfig { @Before("execution(* com.lzlearn.service.*.*(..))") public void start(){ System.out.println("前置方法"); } @AfterReturning("execution(* com.lzlearn.service.*.*(..))") public void after(){ System.out.println("后置方法"); } @After("execution(* com.lzlearn.service.*.*(..))") public void finalMethod(){ System.out.println("最终方法"); } @AfterThrowing("execution(* com.lzlearn.service.*.*(..))") public void errMethod(){ System.out.println("异常方法"); } } ``` 或者进行环绕增强 ``` @Around("execution(* com.lzlearn.service.*.*(..))") public Object around(ProceedingJoinPoint proceedingJoinPoint){ Object result = null; try { System.out.println("开启事务"); result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs()); System.out.println("提交事务"); } catch (Throwable throwable) { System.out.println("回滚事务"); throwable.printStackTrace(); } finally { System.out.println("关闭事务"); } return result; } ``` 这里解释一下("execution(* com.lzlearn.service.*.*(..))") 1、execution(): 表达式主体。 2、第一个*号:表示返回类型, *号表示所有的类型。 3、包名:表示需要拦截的包名,后面的两个句点表示当前包和当前包的所有子包,com.lzlearn.service包、子孙包下所有类的方法。 4、第二个*号:表示类名,*号表示所有的类。 5、*(..):最后这个星号表示方法名,*号表示所有的方法,后面括弧里面表示方法的参数,两个句点表示任何参数