spring框架
-
介绍
Spring 是 Java EE 编程领域的一款轻量级的开源框架,由被称为“Spring 之父”的 Rod Johnson 于 2002 年提出并创立,它的目标就是要简化 Java 企业级应用程序的开发难度和周期。 -
优势
2.1 轻量级的框架
2.2 低侵入式 、低污染
2.3 很好的整合其它框架;可以让任何模块独立起来
2.4 提供Web层的解决方案
2.5 提供了强大的、易用的事务管理机制
2.6 提供了强大的单元测试功能 -
核心功能
1.Ioc和DI
Ioc:控制反转,将对象的管理交给了spring容器,
1.对象的声明周期 创建、使用、销毁等等
2.对象之间的依赖(DI 依赖注入)
2.AOP:面向切面编程
IoC
spring的xml文件配置
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<beans>
标签中可以配置适用于全局的属性
例如:标签中配置default-lazy-init
属性是设置该容器下所有的bean是否延时加载
spring容器
注册bean 注册对象
默认情况下,在容器加载期间就会创建所有的对象,并且每个对象都是单例
<bean>标签中的属性值
-
id:bean的唯一标识,通过id获取注册的对象
-
class:类型,根据指定的类型通过反射机制创建对象,默认情况下是通过无参构造方法创建
-
lazy-init:是否延时加载该对象 (default/false:不使用延时加载,在创建容器时,就会创建该对象
true:在加载容器时不创建该对象,调用getBean方法时,才会创建该对象) -
scope:设置对象的作用范围(singleton(默认):单例
prototype:原型 每次通过getBean获取对象时,都会新创建一个该对象
web相关 : request:该对象的作用域为request域
session:该对象的作用域为session域 ) -
init-method:指定该对象的初始化方法,在对象创建完成之后,调用该方法
-
destroy-method:指定该对象的销毁方法
当没有为bean指定名称(id/name),名称为 全限定类名#index
name的作用和id一样,name可以为该bean起多个名称 空格隔开即可
DI(依赖注入)
- 属性注入(setter注入)
- 构造器注入
- 自动装配
- 工厂注入
属性注入
<bean id="student" class="com.lanou.Student">
name:属性名 例如name=“id” 通过setId方法为该属性赋值
value:为该属性赋的值
<--注入list集合-->
<property name="li" >
<list>
<value>10</value>
<value>20</value>
<value>30</value>
</list>
</property>
<-- 注入数组 -->
<property name="arr">
<array>
<value>4</value>
<value>5</value>
</array>
</property>
<!-- 注入map -->
<property name="map">
<map>
<entry key="id">
<value>10</value>
</entry>
<entry key="name">
<value>李四</value>
</entry>
</map>
</property>
引入其它对象
<--容器中没有StudentDao对象 -->
<property name="StudentDao">
<bean class="com.lanou.StudentDao"></bean>
</property>
<!-- 容器中有StudentDao对象 -->
<!--
ref:引用spring容器中已经注册的对象,要引用对象的id值
-->
<!-- <property name="studentDao" ref="studentDao"></property> -->
构造器注入
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-v895r3PZ-1656934756153)(1.png)]
<!-- 构造器注入 -->
<bean id="student2" class="com.lanou.Student">
<!-- 自上而下为构造方法的第一个参数,第二个参数,....赋值.. -->
<!-- <constructor-arg value="10"></constructor-arg>
<constructor-arg value="张三"></constructor-arg> -->
<!-- index:参数的位置,从0开始 -->
<!-- <constructor-arg index="1" value="名字"></constructor-arg>
<constructor-arg index="0" value="1"></constructor-arg> -->
<!-- name:形参名 -->
<constructor-arg name="id" value="1"></constructor-arg>
<constructor-arg name="name" value="aa"></constructor-arg>
<constructor-arg name="li">
<list>
<value>10</value>
<value>20</value>
</list>
</constructor-arg>
自动装配
-
byName:如果容器中某个bean的id和对象中某个set方法匹配,
将该bean通过setter注入到该对象;如果找不到同名的,抛出异常 -
byType:如果容器中某个bean的类型和对象中某个set方法的参数类型匹配,
将该bean通过setter注入到该对象;如果找不到该类型的bean,就不注入
如果找到多个同类型的bean,抛出异常 -
constructor:通过构造方法进行注入,
1.先按照构造方法的参数类型,从容器中找同类型的bean
如果没找到不注入。如果找到一个,将该bean注入进去。(类似于byType)2.如果找到多个同类型的,在同类型的这些bean中,如果某个bean的
id和构造方法的参数名一致,将同名的注入进去。(byName)3.如果没找到同名的,就不注入了
工厂模式
帮助我们创建对象,隐藏了对象的创建以及初始化细节,使用者只需要知道对象的名称即可,需要使用某个对象时,根据名称从工厂获取该对象即可
简单工厂
- 实例工厂
- 抽象工厂
实例工厂注入
<!-- 1.将工厂注册到spring -->
<bean id="animalFactory" class="com.lanou.factory.AnimalFactory"></bean>
<!--
factory-bean:工厂对象的id
factory-method:工厂中负责创建对象的方法
-->
<bean id="dog" factory-bean="animalFactory" factory-method="getAnimal1">
<!-- 为factory-method方法传参 -->
<constructor-arg value="dog"></constructor-arg>
</bean>
** 静态工厂注入 **
<!--
class:工厂的类名
factory-method:创建对象的静态方法
-->
<bean id="cat" class="com.lanou.factory.AnimalFactory" factory-method="getAnimal">
<constructor-arg value="cat"></constructor-arg>
</bean>
注解
@Configuration:配置类,本质上这个类和配置文件是一个级别的
@ComponentScan(basePackages = {“com.lanou”},basePackageClasses = SpringConfig.class)相当于>配置文件的context:component-scan标签
多个同类型的bean,我们通过byType获取时,优先获取@Primary修饰的
@Primary
从容器中找到MyService对象,赋值给了方法的参数
public StudentController studentController(@Autowired MyService myService) {
System.out.println(myService);
StudentController sc = new StudentController();
sc.setMyService(myService);
return sc;
}
注解(配置)类加载
ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
-
@Component(“mc”):将当前类的对象注册到spring容器中,id默认为首字母小写的类名
value属性可以为对象指定id的值 -
@Lazy(value = false):是否延时加载 等同于bean的lazy-init属性
-
@Scope(scopeName = “singleton”):等同于bean标签的scope属性
向Controller层注入service层
@Autowired
默认为byType
required:默认值为true
true:当前对象必须依赖注入的对象,如果找不到合适的bean注入,就抛出异常
false:如果找不到合适的bean,就不注入了
@Qualifier(“myServiceImpl”):配合@Autowired 以byName的方式查找合适的bean注入
@Resource(name = “myServiceImpl”):java自带的注入注解
@PostConstruct相当于init-met
@PreDestroy相当于destory-method
spring文件中的配置
扫描指定的包,根据每个类的注解,将对应的对象注册进spring容器
base-package:要扫描的包;会扫描此包,以及此包的子孙包
被扫描的类上面有@Component、@Controller、@Service、@Repository、@RestController等注解
就会被注册到spring容器中
字段上面有@Autowired,从容器中找合适的bean进行依赖注入
<context:component-scan base-package="com.lanou"></context:component-scan>
代理模式
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
-
目标对象(target Class):实现了核心功能的对象
-
代理对象(proxy Class):在代理类中包含了目标对象,可以对目标对象的访问做控制。在目标对象的功能开始之前或者结束之后等时机添加额外功能。
-
抽象类:制定规范,可以使接口或者抽象类;一般情况下,目标类和与之对应的代理类实现同一个接口或者继承同一个抽象类,使用者不论使用代理还是目标对象 所做的操作是一样的。
代理模式的实现;
- 静态代理:在编译期间,就需要定义好代理类
- 动态代理:在运行时,根据需要生成代理类 例如mybatis中的getMapper方法
JDK动态代理(接口代理):根据接口,生成接口的实现类作为代理类。目标类必须有接口
CGLIB动态代理:根据目标类生成目标类的子类(派生类)作为代理类。目标类有没有接口都行
CGLIB效率高于JDK动态代理
类似于拦截器的类,当动态生成代理对象调用方法时,会去执行拦截器中的方法,在拦截器的方法中,我们处理功能。实现还是通过反射机制
静态代理:自行创建功能类,并将功能类的方法装饰在目标类的目标方法上
动态代理:
-
JDK动态代理
实现InvocationHandler接口 并实现invoke方法
通过JDK动态代理生成的代理对象,调用方法时,就会执行invoke方法- 参数:
- 1.代理对象
- 2.目标对象中对应的方法
- 3.2中方法需要的参数
返回值就是method方法执行完之后的返回值
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(“invoke”);
tx.begin();
try {
//执行目标对象中的方法
return method.invoke(this.target, args);
} catch (Exception e) {
tx.rollback();
}finally {
tx.commit();
}return null;
}
public static void main(String[] args) {
//目标类
StudentDao target = new StudentDaoTatget();
//需要装饰目标类方法的工具类
TransactionAspect tx = new TransactionAspect();
MyHandler mh = new MyHandler(target, tx);//动态生成代理对象 /* * 1.loader:类加载器 * 2.interfaces:目标类所实现的接口 * 3.h:invocationHandler对象,通过生成代理对象调用方法时,就回去回调指定 * 的handler对象中的invoke方法。 */ StudentDao proxy = (StudentDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), mh);
S ystem.out.println(proxy.getClass());
proxy.update(1);
}
2.CGLIB动态代理
public static void main(String[] args) {
MethodInterceptor mi = new MethodInterceptor() {
private StudentDao target = new StudentDaoTatget();
private TransactionAspect tx = new TransactionAspect();
/*
* MethodProxy:为需要执行的方法生成的代理对象,
* 据说,使用该方法代理执行目标对象中的方法效率高
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("intercept");
tx.begin();
try {
//return method.invoke(this.target, args);
return methodProxy.invokeSuper(proxy, args);
} catch (Exception e) {
tx.rollback();
}finally {
tx.commit();
}
return null;
}
};
//通过CGLIB生成代理对象
Enhancer enhancer = new Enhancer();
//将目标类设置为父类
enhancer.setSuperclass(StudentDaoTatget.class);
//设置方法拦截器,通过代理对象调用方法时,就会执行拦截器中的intercept方法
enhancer.setCallback(mi);
//生成代理对象
StudentDaoTatget proxy = (StudentDaoTatget)enhancer.create();
System.out.println(proxy.getClass());
proxy.delete();
}
对应的类文件如下
AOP概念:
- 目标对象:拥有核心功能的对象
- 代理对象:是目标对象的一个代理方,在代理对象中,在合适的时机为目标对象中的方法添加额外方法。例如方法执行之前,之后等等。
- 连接点:目标对象中可执行的方法,这些方法都可以被添加额外功能。
- 切入点:本质上就是一个表达式,符合该表达式的连接点需要被添加额外功能
- 切面:就是一个类,这个类中定义着额外功能。
- 通知:切面类中的那些方法,都可以是通知。
1.前置通知
2.后置通知
3.异常通知
4.最终通知
5.环绕通知 - 织入:根据目标对象和切面类动态生成代理对象的过程。
AOP:面向切面的编程,某些非业务核心功能,但是整个系统中多个对象中都需要使用,此时,我们可以通过AOP来动态的为核心对象添加这些额外的功能,降低了非核心功能和核心功能的耦合度。后期正价好维护。例如 事务、日志等功能。
AOP配置文件
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 目标对象 -->
<bean id="target" class="com.lanou.dao.StudentDaoTatget"></bean>
<!-- 切面对象 -->
<bean id="myAspect" class="com.lanou.aspect.MyAspect"></bean>
<!-- aop相关配置
proxy-target-class:默认值为false,是用来指定用哪种方式生成代理对象
false:如果目标类有接口,就使用JDK动态代理;如果没有接口,就使用CGLIB
true:只使用CGLIB动态代理
-->
<aop:config proxy-target-class="false">
<!-- 切入点配置 -->
<aop:pointcut expression="execution(* com.lanou.dao..*.*(..))" id="pc"/>
<!-- 切面 -->
<aop:aspect ref="myAspect">
<aop:before method="before" pointcut-ref="pc"/>
<aop:after-returning method="afterReturning" pointcut-ref="pc"/>
<aop:after-throwing method="afterThrowding" pointcut-ref="pc"/>
<aop:after method="after" pointcut-ref="pc"/>
<aop:around method="around" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
</beans>