一、Spring是什么?
对于面试者回答什么是Spring,这个问题占6分分值,分值点分布:
1、Spring的核心是一个轻量级(Lightweight)的容器(Container)。
2、Spring是实现IoC(Inversion of Control)容器和非入侵性(No intrusive)的框架。
3、Spring提供AOP(Aspect-oriented programming)概念的实现方式。
4、Spring提供对持久层(Persistence)、事物(Transcation)的支持。
5、Spring供MVC Web框架的实现,并对一些常用的企业服务API(Application Interface)提供一致的模型封装。
6、Spring提供了对现存的各种框架(Structs、JSF、Hibernate、Ibatis、Webwork等)相整合的方案。
总之,Spring是一个全方位的应用程序框架。
Spring框架主要由七部分组成,分别是 Spring Core、 Spring AOP、 Spring ORM、 Spring DAO、Spring Context、 Spring Web和 Spring Web MVC。
## Spring优点
1.方便解耦,简化开发
通过Spring提供的IoC容器,我们可以将对象之间的依赖关系交由Spring进行控制,避免硬编码所
造成的过度程序耦合。有了Spring,用户不必再为单实例模式类、属性文件解析等这些很底层的需
求编写代码,可以更专注于上层的应用。
2.AOP编程的支持
通过Spring提供的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过
AOP轻松应付。
3.声明事物的支持
在Spring中,我们可以从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活地进行事务的
管理,提高开发效率和质量。
4.方便程序的测试
可以用非容器依赖的编程方式进行几乎所有的测试工作,在Spring里,测试不再是昂贵的操作,
而是随手可做的事情。例如:Spring对Junit4支持,可以通过注解方便的测试Spring程序。
5.方便集成各种优秀框架
Spring不排斥各种优秀的开源框架,相反,Spring可以降低各种框架的使用难度,Spring提供了
对各种优秀框架(如Struts,Hibernate、Hessian、Quartz)等的直接支持。
6.降低Java EE API的使用难度
Spring对很多难用的Java EE API(如JDBC,JavaMail,远程调用等)提供了一个薄薄的封装层,
通过Spring的简易封装,这些Java EE API的使用难度大为降低。
。
二、使用步骤
1.导包
commons-logging-1.2.jar
spring-core-4.3.6.RELEASE.jar
spring-context-4.3.6.RELEASE.jar
spring-beans-4.3.6.RELEASE.jar
spring-expression-4.3.6.RELEASE.jar
2.编写xml配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<bean id="userdaoim" class="main.java.userdaoim"/>
</beans>
3.调用Spring的核心容器
Spring框架主要是通过其核心容器来实现:
BeanFactory
ApplicationContext为前者的子接口,额外添加了对国际化,资源访问,事件传播等方面的支持
ApplicationContext两种创建方式:
1.ClassPathXmlApplicationContext
从类路径中寻找
ApplicationContext app = new ClassPathXmlApplicationContext("/resourse/applicationContext.xml");
2.FileSystemXmlApplicationContext
从绝对路径中寻找
new FileSystemXmlApplicationContext()
获取bean
app.getBean(beanid); 需要转型
app.getBean(beanid.class)
三、依赖注入(SpringIoc)
依赖注入和控制反转含义相同,只不过这两个称呼是从不同的角度来叙述同一个概念
控制反转:当调用者需要java对象时,通常会new 一个,但使用spring容器之后,spring容器会负责控制程序之间的关系,控制权由应用代码转移到了spring容器,控制权发生了反转。
依赖注入:从spring容器来看,spring容器负责将依赖对象赋值给调用者的成员变量,这相当于为调用者注入了它的依赖实例
实现方式
set注入
1.配置xml
2.被注入的属性,需要实现set方法
private String name;
public void setName(String name) {//配置文件使用property的前提
this.name = name;
}
构造器注入
配置xml
既然要注入那么就是有参构造函数
四、Bean
Bean实例化
构造器实例化
默认无参方式实例化
1.一个有无参构造器的类
2.配置bean
3.通过容器调用
静态工厂实例化
1.一个工厂类包含一个静态的返回一个所需对象类型的方法
2.配置工厂类的bean,factory-method=“静态方法名”
<bean id="user2" class="org.sang.User2Factory" factory-method="getInstance"/>
实例工厂实例化
1.一个工厂类,只是原来方法不是静态的
2.配置工厂类bean
3.再配置y一个bean
facotry-bean—>该工厂类
factory-method–>该方法
<bean class="org.sang.User3Factory" id="user3Factory"/>
<bean id="user3" factory-bean="user3Factory" factory-method="getUser3"/>
Bean作用域
作用域名称 | 说明 |
---|---|
singleton (默认的) | 在每个Spring IoC容器中,一个bean定义对应只会有唯一的一个bean实例。 |
prototype | 一个bean定义可以有多个bean实例。 |
request | 一个bean定义对应于单个HTTP 请求的生命周期。也就是说,每个HTTP 请求都有一个bean实例,且该实例仅在这个HTTP 请求的生命周期里有效。该作用域仅适用于WebApplicationContext环境。 |
session | 一个bean 定义对应于单个HTTP Session 的生命周期,也就是说,每个HTTP Session 都有一个bean实例,且该实例仅在这个HTTP Session 的生命周期里有效。该作用域仅适用于WebApplicationContext环境。 |
application | 一个bean 定义对应于单个ServletContext 的生命周期。该作用域仅适用于WebApplicationContext环境。 |
websocket | 一个bean 定义对应于单个websocket 的生命周期。该作用域仅适用于WebApplicationContext环境。 |
globalSession | 在一个全局的HTTP Session ,容器会返回同一个实例,仅限于使用portlet上下文时有效 |
Portlet规范定义了全局Session的概念,它被所有构成某个 portlet web应用的各种不同的portlet所共享。
Bean生命周期
简单点说就是:bean的实例化–>bean的初始化–>bean的使用–>bean的销毁
1.实例化:也就是new一个对象
2.属性注入:Spring上下文对实例化的bean进行配置(IOC注入)
3.设置beanId:如果实现BeanNameAware接口,调用setBeanName()方法设置ID
4.调用BeanFactoryAware.setBeanFactory(setBeanFactory(BeanFactory):可以用这个方式来获取其它Bean,只需在Spring配置文件中配置一个普通的Bean就可以;
5.调用ApplicationContextAware.setApplicationContext(ApplicationContext):与BeanFactoryAware.setBeanFactory同样作用,但是ApplicationContextAware是子接口,可以实现更多接口;
6.实例化之前调用:BeanPostProcessor.postProcessBeforeInitialization(Object obj, String s)方法调用,
7.实例化:如果在spring配置中还配置了init-method属性,会自动调用该方法;
8.实质化之后调用:如果关联BeanPostProcessor接口,调用postProcessAfterInitialization(Object obj, String s)方法,
注:前面这里我们就完成bean的实例化;
9.bean的销毁:当bean不再被使用时,就会调用destroy()方法;
10.bean销毁调用方法:如果配置了destroy-method方法,会自动调用该方法;
————————————————
版权声明:本文为CSDN博主「Rick1024」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/keenstyle/article/details/104820909
Bean的装配
无外乎就是注入bean,配置bean
xml
set注入
条件:
1.bean类提供一个无参构造器
2.注入的属性具有set方法
<bean id="student" class="com.ius.demo.Student" lazy-init="true" >
<property name="tTT" value="东东" >< /property >
</bean >
构造注入
条件:
1.提供带有参数的有参构造方法
<bean id="student" class="com.ius.demo.Student" lazy-init="true" scope="singleton" >
<constructor-arg index="0" value="tom"/>
<constructor-arg index="1" >
<list>
<value>"list1"</value>
<value>"list2"</value>
</list>
</constructor-arg>
</bean >
注解
优点:不用在xml为每个bean配置id.calss
直接通过扫描包注解即可,包扫描需要导包(spring-aop-4.36…jar)
(1)@Repository 一般用于数据访问(数据访问(持久)层组件,实现dao访问)
(2)@Service 一般用于服务(业务层组件,处理业务逻辑,比如注入并操作dao)
(3)@Controller 一般用于控制器(控制层组件)
(4)@Component 一般用于自定义组件,把普通类实例化到spring容器中,相当于配置文件中的
(5)@Autowired 根据类型 基本等价于 @Resource(name=“”)
1.配置bean
@Service("userdaoim")
public class userdaoim implements usedao {
2.注入bean
@Resource(name = "user") ==@Autowired
user use;
3. //@Value("张三")
@Value("${name}")-->配置了properties文件
private String name;
当一个类在spring配置文件中配置了其id,那么它就交给了spring管理,如果下次使用时重新new,那么其通过spring来注入的属性将为空
自动装配
==autowire= byName ==
自动根据属性名注入
<bean id="student" class="com.ius.demo.Student" lazy-init="true" autowire="byName" >
</bean >
Aop
面向切面编程
Spring注意到AspectJ在AOP的实现方式上依赖于特殊编译器(ajc编译器),因此Spring很机智回避了这点,转向采用动态代理技术的实现原理来构建Spring AOP的内部机制(动态织入),这是与AspectJ最根本的区别。在AspectJ 1.5后,引入@Aspect形式的注解风格的开发,Spring也非常快地跟进了这种方式,因此Spring 2.0后便使用了与AspectJ一样的注解。
请注意,Spring 只是使用了与 AspectJ 5 一样的注解,但仍然没有使用 AspectJ 的编译器,底层依是动态代理技术的实现,真正的AspectJ参考
https://zhuanlan.zhihu.com/p/25522841
提供了一个专门的编译器(ajc),在编译时提供横向代码的静态织入
术语
1 织入
将切面代码插入到目标对象,从而生成代理对象的过程
2 切面(Aspect)
封装横切关注点信息的类,每个关注点体现为一个通知方法。
3 通知(Advice)
切面中的方法
4 目标(Target)
被通知的对象
5 代理(Proxy)
向目标对象应用通知之后创建的代理对象
6 连接点(Joinpoint)
方法的调用
7 切入点(pointcut):
类名或方法名
SpringAop(动态代理)
纯java代码实现,不需要专门的编译过程和类加载器
JDK动态代理
Java.lang.reflect.Proxy类实现
条件:目标必须实现接口
实现过程:
1.编写代理类实现接口
2.重写invoke()
原理:在代理类中利用反射生成一个代理类对象
CGLIB代理
不用实现接口,拿类来制造子类
实现过程:
1.编写代理类实现接口
2.重写intercept()
在切面编程时时spring默认为JDK动态代理
这导致生成的代理对象只能转化为接口类型,若想转化为实现类则需要
改为CGLIB代理
<aop:aspectj-autoproxy proxy-target-class=“true”/>
基于代理类的AOP
Spring 通知类型
Around 环绕通知 org.aopalliance.intercept.MethodInterceptor 拦截对目标方法调用
Before 前置通知 org.springframework.aop.MethodBeforeAdvice 在目标方法调用前调用
After 后置通知 org.springframework.aop.AfterReturningAdvice 在目标方法调用后调用
Throws 异常通知 org.springframework.aop.ThrowsAdvice 当目标方法抛出异常时调用
引介通知 在目标类中添加一些新的方法和属性
引介通知的使用
1.在切面类中配置,这里是基于AspectJ的注解式切面类
2.UserDao为目标,Animal为通知接口,AnimalImp为通知接口实现类
其实就是为UserDao添加Animal中的方法
//引介通知
@DeclareParents(value = "com.wz.aspectj.target.UserDao+", defaultImpl =AnimalImp.class)
public Animal animal;
使用
得到的对象需要强转
UserDao userDao = (UserDao) applicationContext.getBean("userDao");
// 2 执行方法
// userDao.addUser();
userDao.delect();
Animal animal=(Animal) userDao;
————————————————
ProxyFactoryBean
条件:导入aoplliance-1.0.jar
实现过程:
1.编写切面类
2.配置xml
AspectJ开发
xml
条件:
步骤:
1.xml中定义切面bean
2.配置切面(切入点,通知类型)
3.编写切面类
<bean id="myAspect" class="com.xml.MyAspect"/>
<aop:config>
<aop:aspect id="aspect" ref="myAspect">
<aop:pointcut expression="execution(* com.xml.UserDaoImpl.*(..))" id="myPointCut"/>
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="returnVal"/>
<aop:around method="myAround" pointcut-ref="myPointCut"/>
<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
<aop:after method="myAfter" pointcut-ref="myPointCut"/>
</aop:aspect>
</aop:config>
public class MyAspect {
// 前置通知
public void myBefore(JoinPoint joinPoint) {
System.out.print("前置通知 :模拟执行权限检查...,");
System.out.print("目标类是:"+joinPoint.getTarget() );
System.out.println(",被织入增强处理的目标方法为:"
+joinPoint.getSignature().getName());
}
// 后置通知
public void myAfterReturning(JoinPoint joinPoint) {
System.out.print("后置通知:模拟记录日志...," );
System.out.println("被织入增强处理的目标方法为:"
+ joinPoint.getSignature().getName());
}
// 环绕通知
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
// 开始
System.out.println("环绕开始:执行目标方法之前,模拟开启事务...");
// 执行当前目标方法
Object obj = proceedingJoinPoint.proceed();
// 结束
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...");
return obj;
}
// 异常通知
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("异常通知:" + "出错了" + e.getMessage());
}
// 最终通知
public void myAfter() {
System.out.println("最终通知:模拟方法结束后的释放资源...");
}
}
注解
优点:不用配置aop:config
步骤:
1.编写切面类。额外加上切入点,并加上注解
2.xml中配置包扫描和基于注解的声明式AspectJ支持
<!-- 指定需要扫描的包,使注解生效 -->
<context:component-scan base-package="com.wz" />
<!-- 启动基于注解的声明式AspectJ支持 -->
<aop:aspectj-autoproxy />
@Aspect
@Component
public class MyAspect {
// 定义切入点表达式
@Pointcut("execution(* com.wz.aspectj.target.UserDao.delect(..))")
//定义切入点名称:通过定义方法来表示切入点名称 (一个返回值为void、方法体为空的方法)
//切入点名称将作为参数传递给需要执行增强的通知方法
private void myPointCut(){}
// 前置通知
@Before("myPointCut()")
public void myBefore(JoinPoint joinPoint) {
System.out.print("前置通知 :模拟执行权限检查...,");
System.out.print("目标类是:"+joinPoint.getTarget() );
System.out.println(",被织入增强处理的目标方法为:"
+joinPoint.getSignature().getName());
}
// 后置通知
@AfterReturning(value="myPointCut()")
public void myAfterReturning(JoinPoint joinPoint) {
System.out.print("后置通知:模拟记录日志...," );
System.out.println("被织入增强处理的目标方法为:"
+ joinPoint.getSignature().getName());
}
// 环绕通知
@Around("myPointCut()")
public Object myAround(ProceedingJoinPoint proceedingJoinPoint)
throws Throwable {
// 开始
System.out.println("环绕开始:执行目标方法之前,模拟开启事务...");
// 执行当前目标方法
Object obj = proceedingJoinPoint.proceed();
// 结束
System.out.println("环绕结束:执行目标方法之后,模拟关闭事务...");
return obj;
}
// 异常通知
@AfterThrowing(value="myPointCut()",throwing="e")
public void myAfterThrowing(JoinPoint joinPoint, Throwable e) {
System.out.println("异常通知:" + "出错了" + e.getMessage());
}
// 最终通知
@After("myPointCut()")
public void myAfter() {
System.out.println("最终通知:模拟方法结束后的释放资源...");
}
}
注解(第二次学习学到)
第二步xml可以省略,使用Springconfig配置类