HelloSpring
Hello 对象是谁创建的?
hello对象是由Spring创建的
Hello 对象的属性是怎么设置的?
hello对象的属性是由Spring容器设置的
IOC本质
IOC是一种思想,而依赖注入(DI)只是它的一种实现。
Spring过程:Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从IOC容器中取出需要的对象。XML配置Bean时,Bean的定义信息和实现是分离的,而是采用注解的方式将两者合为一体,最新版的Spring已经可以零配置实现IOC,主要是因为Bean的定义信息以注解的形式定义在实现类中。
控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式,Spring中实现控制反转的是IOC容器,其实现方法是依赖注入(DI)。
使用spring来创建对象
<bean id="hello" class="Hello">
<property name="str" value="Spring"> </property>
</bean>
2.IOC创建对象
1.使用无参构造,创建对象 默认
public Usert() {
System.out.println("usert被创建了");
}
xml
<bean id="usert" class="com.pojo.Usert">
<property name="name" value="xfn">
</property>
2.使用有参构造创建对象
1.类型赋值
在前面的场景中,容器 可以 使用简单类型的类型匹配 使用显式指定构造函数参数的类型 type
属性。 例如:
<bean id = "exampleBean" class = "examples.ExampleBean" >
<constructor-arg type = "int" value = "7500000" />
<constructor-arg type = "java.lang.String" value = "42" / >
</bean>
下标赋值
使用 index
明确指定的属性 构造函数参数的索引。 例如:
<bean id = "exampleBean" class = "examples.ExampleBean" >
<constructor-arg index = "0" value = "7500000" />
<constructor-arg index = "1" value = "42" />
</bean >
构造函数参数名称
从 Spring 3.0 开始,您还可以使用构造函数参数 值消歧的名称:
<bean id = "exampleBean" class = "examples.ExampleBean" >
<constructor-arg name = "years" value = "7500000" />
<constructor-arg name = "ultimateanswer" value = "42" />
</bean >
总结,在配置文件加载的时候,容器中管理的对象就已经初始化了
3.Spring配置
3.1 别名
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iiTspmOx-1658999117399)(C:\Users\21886\AppData\Roaming\Typora\typora-user-images\image-20220224104414308.png)]
3.2 beans的配置
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-QTUYZDEJ-1658999117400)(spring.assets/image-20220224105218027.png)]
3.3import导入
4.DI依赖注入
4.1构造器注入
4.2 set方式注入
依赖注入: Set注入!
。依赖: bean对象的创建依赖于容器
I
。注入: bean对象中的所有属性,由容器来注入!|
bean | ref | idref | list | set | map | props | value | null
4.3其他方式注入
带有 p 命名空间的 XML 快捷方式
带有 c 命名空间的 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:p="http://www.springframework.org/schema/p"
xmlns:c= "http://www.springframework.org/schema/c"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="user" class="com.pojo.User" p:name="陈平安" p:age="18">
</bean>
<bean id="user2" class="com.pojo.User" c:name="徐凤年" c:age="17"/>
</beans>
5.bean作用域
Scope | Description |
---|---|
singleton | (Default) Scopes a single bean definition to a single object instance per Spring IoC container. |
prototype | Scopes a single bean definition to any number of object instances. |
request | Scopes a single bean definition to the lifecycle of a single HTTP request; that is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext . |
session | Scopes a single bean definition to the lifecycle of an HTTP Session . Only valid in the context of a web-aware Spring ApplicationContext . |
global session | Scopes a single bean definition to the lifecycle of a global HTTP Session . Typically only valid when used in a portlet context. Only valid in the context of a web-aware Spring ApplicationContext . |
5.1单例模式(spring默认机制)
<bean id="user" class="com.pojo.User" p:name="陈平安" p:age="18" scope="singleton"/>
5.2 原型模式:每次从容器中get的时候,都会产生一个新对象(多线程)
<bean id = "accountService" class = "com.foo.DefaultAccountService" scope = "prototype" />
request,session,global,session只在web开发中使用
6.bean的自动装配
byName:自动在容器上下文中查找。和自己对象set方法后面的值对应的beanid!
<bean id="cat" class="com.pojo.Cat"></bean>
<bean id="dog" class="com.pojo.Dog"></bean>
<bean id="people" class="com.pojo.People" autowire="byName">
<property name="name" value="陈平安"></property>
</bean>
byType:自动在容器上下文中查找,和自己对象属性类型相同的bean!
<bean class="com.pojo.Cat"></bean>
<bean class="com.pojo.Dog"></bean>
<bean id="people" class="com.pojo.People" autowire="byType">
<property name="name" value="陈平安"></property>
</bean>
总结
byname的时候,需要保证所有bean的id唯一,并且这 个bean需要和自动注入的属性的set方法的值一致!
bytype的时候,需要保证所有bean的class唯一 , 并且这个bean需要和自动注入的属性的类型-致!
7.使用注解实现自动装配
开启注解
<context:annotation-config/>
@Autowired
直接在属性上使用即可!也可以在set方式上使用!
使用Autowired我们可以不用编写Set方法了,前提是你这个自动装配的属性在I0C (Spring) 容器中存在,且符
合名字byname!
@Autowired源码
public @interface Autowired {
boolean required() default true;
}
//如果显示定义了Autowired的required属性为false,说明这个对象可以为nu11, 否则不允许为空
@Autowired( required = false)
private Cat cat;
如果@Autowired自动装配的环境比较复杂,自动装配无法通过一个注解@Autowired]完成的时候、我们可以
使用@Qualifier(value=“xx”)去配置@Autowired的使用,指定一个唯一的bean对象注入!
pub1ic class People {
@Autowired
@qualifier(va1ue="cat111")
private Cat cat;
@Autowired
@qualifier(value=" dog222")
private Dog dog;
private string name;
}
@Resource
自动装配通过名字。类型
@Resource
private Cat cat;
// @Autowired
// @Qualifier(value = "dog22")
@Resource(name = "dog23")
private Dog dog;
@Component
代表组件
@Component
public class User {
@Value("fengnian")
public String name ;
@Value("xufengnian")
public void setName(String name) {
this.name = name;
}
}
@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层!
。dao [@Repository]
。service [@Service ]
。controller , @Controller]
这四个注解功能都是一样的, 都是代表将某个类注册到Spring中,装配Bean
作用域
@Component
@Scope
public class User {
@Value("fengnian")
public String name ;
相当于<property name="name" value="xufengnian"
@Value("xufengnian")
public void setName(String name) {
this.name = name;
}
}
总结
xml与注解:
。xml更加万能,适用于任何场合!维护简单方便
。注解不是自己类使用不了,维护相对复杂!
xml与注解最佳实践:
。xml用来管理bean;
。注解只负责完成属性的注入;
。必须让注解生效,就需要开启注解的支持
<!--指定 要扫描的包,这个包下的注解就会生效-->
<context:component-scan base-package="com"/>
<context:annotation-config/>
8.使用Javaconfig实现配置
@Configuration
代表这是配置类,和beans.xml一样
@Configuration
public class config2 {
}
@ComponentScan
扫描包,引入配置类的地址
@ComponentScan("com.pojo")
@bean
//注册一个bean ,就相当 之前写的个bean标签
//这个方法的名字,就相当fbean标签中的id属性
//这个方法的返回值,就相当J bean标签中的class属性
@Configuration
@ComponentScan("com.pojo")
@Import(config2.class)
public class config {
@Bean
public User getUser(){
return new User();//就是返回要注入到bean的对象
}
}
注意!如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig 上下 文来获取容器,通过配置类的class对象加载
public class test {
public static void main(String[] args) {
如果完全使用了配置类方式去做,我们就只能通过AnnotationConfig 上下 文来获取容器,通过配置类的class对象加载!
ApplicationContext context = new AnnotationConfigApplicationContext(config.class);
User getUser = (User) context.getBean("getUser");
System.out.println(getUser.getName());
}
}
@Import 引入配置类的class对象
@Configuration
@ComponentScan("com.pojo")
@Import(config2.class)
public class config {
@Bean
public User getUser(){
return new User();
}
}
9.代理模式
角色分析:
●抽象角色: -般会使用接口或者抽象类来解决
●真实角色:被代理的角色
●代理角色:代理真实角色,代理真实角色后,我们一般会做一-些附属操作
●客户:访问代理对象的人! .
静态代理
代码步骤: .
1.接口
package com.zsr.demo01;
//租房
public interface Rent {
public void rent();
}
2.真实角色
package com.zsr.demo01;
public class Host implements Rent {
public void rent(){
System.out.println("房东要出租房子");
}
}
3.代理角色
package com.zsr.demo01;
public class Proxy {
private Host host;
public Proxy() {
}
public Proxy(Host host) {
this.host = host;
}
public void rent(){
host.rent();
setHost();
hetong();
fare();
}
//看房
public void setHost(){
System.out.println("中介带你开房");
}
//中介收费
public void hetong(){
System.out.println("签订合同");
}
//中介收费
public void fare(){
System.out.println("中介收费");
}
}
4.客户端访问代理角色
package com.zsr.demo01;
public class Clinet {
public static void main(String[] args) {
//调用 房东要租房子
Host host = new Host();
//中介帮房东租房子,但是呢?代理角一一般会有-些附属操作!
Proxy proxy = new Proxy();
//你不用面对房东,直接找中介租房即可!
proxy.rent();
}
}
代理模式的好处:
●可以使真实角色的操作更加纯粹!不用去关注一些公共的业务
●公共也就就交给代理角色!实现了业务的分工!
●公共业务发生扩展的时候,方便集中管理!
缺点:
●一个真实角色就会产生一个代理角色;代码量会翻倍,开发效率降低
AOP实现机制
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-iKsywaO9-1658999117409)(spring.assets/image-20220225205647381.png)]
动态代理
动态代理的本质 反射机制实现
●动态代理分为两大类:基于接口的动态代理, 基于类的动态代理
。基于接口— JDK动态代理[我们在这里使用]
。基于类: cglib
。java字节码实现 : javasist
Proxy 代理,
InvocationHandler调用处理程序
代码
public class ProxyInvocationHandler implements InvocationHandler {
/* Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(),
new Class<?>[] { Foo.class },
handler);
*/
private Object target;
public void setTarget(Object target) {
this.target = target;
}
//生成得到代理类
public Object getProxy(){
return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
}
//处理代理实例,并返回结果
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//动态代理的本质 反射机制实现
log(method.getName());
Object result = method.invoke(target, args);
return result;
}
public void log( String msg){
System.out.println("生成了" + msg + "方法");
}
public class Client {
public static void main(String[] args) {
//真实代理
serviceImpi service = new serviceImpi();
//代理角色 不存在
ProxyInvocationHandler proxyInvocationHandler = new ProxyInvocationHandler();
//设置要代理的对象
proxyInvocationHandler.setTarget(service);
//动态生成代理类
service proxy =(service) proxyInvocationHandler.getProxy();
proxy.add();
proxy.delete();
proxy.query();
proxy.update();
}
10.AOP
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-CN0LLR6J-1658999117410)(spring.assets/image-20220226095807979.png)]
实现Spring实现AOP
导入maven依赖
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8</version>
</dependency>
方式一使用原生的Spring API接口
<!--注册bean-->
<bean id="Service" class="com.service.impi.impi"/>
<bean id="log" class="com.service.log"/>
<bean id="afterlog" class="com.service.Afterlog"/>
<!--方式一使用原生的Spring API接口-->
<!--配置aop需要导入aop的约束-->
<aop:config>
<!--切入点:expression 表达式 execution(要执行的位置 修饰符 返回值 类名 方法名 参数) (..)代表任意参数-->
<aop:pointcut id="pointcut" expression="execution(* com.service.impi.impi.*(..))"/>
<!--执行环绕增加-->
<!-- 把log这个类切入到 <aop:pointcut id="printcut" expression="execution(* com.service.impi.*(..))"/>这个方法上面-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
</aop:config>
方式二使用自定义类(切面定义)
<!--方式二 自定义类-->
<bean id="diy" class="com.diy.DiyPointcut"/>
<aop:config>
<!-- 自定义切面 ref要引用的类-->
<aop:aspect ref="diy">
<!-- 切入点-->
<aop:pointcut id="point" expression="execution(* com.service.impi.impi.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
package com.diy;
public class DiyPointcut {
public void before(){
System.out.println("方法执行前");
}
public void after(){
System.out.println("方法执行后");
}
}
package com.service.impi;
import com.service.Service;
public class impi implements Service {
@Override
public void add() {
System.out.println("新增用户");
}
@Override
public void delete() {
System.out.println("删除用户");
}
@Override
public void update() {
System.out.println("修改用户");
}
@Override
public void query() {
System.out.println("查询用户");
}
}
方式三注解开发
@Aspect
标志这个类是一个切面
@Before 执行前
@After执行后
@Around环绕增强
在环绕增强中,我们可以给定一一个参数, 代表我们要获取处理切入的点;
@Aspect
public class AnnotationPointCut {
@Before("execution(* com.service.impi.impi .*(..))")
public void before(){
System.out.println("方法执行前");
}
@After("execution(* com.service.impi.impi .*(..))")
public void after(){
System.out.println("方法执行后");
}
@Around("execution(* com.service.impi.impi .*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable{
System.out.println("环绕前");
Signature signature = joinPoint.getSignature();//获得签名
System.out.println(signature);
Object proceed = joinPoint.proceed();
System.out.println("环绕后");
}
11.Mybatis整合
1.导入相关jar包
。junit
。mybatis
。mysq
。spring相关的
。aop织入
。mybatis-spring
<!-- https://mvnrepository.com/artifact/junit/junit -->
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13.2</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>2.0.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.28</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.3.16</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.8</version>
</dependency>
步骤
1.编写数据源配置
-
sqlSessionFactory
-
sqlSessionTemplate
-
User实体类
-
UserMapper接口
-
UserMapper.xml
<mapper namespace="com.mapper.UserMapper">
<select id="selectUser" resultType="com.pojo.User">
select * from mybatis.user
</select>
spring-dao.xml
<!--DataSource:使Spring的数据源替换Mybatis的配置c3pθ dbcp druid
我们这里使用Spring提供的JDBC : org. springframework. jdbc. datasource
-->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/mybatis"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
</bean>
<!--sqlSessionFactory-->
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<!--绑定mybatis配置文件-->
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath:com/mapper/*.xml"/>
</bean>
<!--SqlSessionTemplate就是常用的sqlSession-->
<bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate">
<!--只能使用构造器注入sqlSessionFactory,因为它没有set方法-->
<constructor-arg ref="sqlSessionFactory" index="0"/>
</bean>
<!--开启注解支持 jdk(expose-proxy="false") cglib (expose-proxy="true")-->
<aop:aspectj-autoproxy expose-proxy="true"/>
</beans>
4.需要给接口加实现类[]
UserMapperImpi
public class UserMapperImpi implements UserMapper {
private SqlSessionTemplate sqlSession;
public void setSqlSession(SqlSessionTemplate sqlSession) {
this.sqlSession = sqlSession;
}
@Override
public List<User> selectUser() {
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();
}
}
5.将自己写的实现类,注入到Spring中,
applicationcontext.xml
<import resource="spring-dao.xml"/>
<!---->
<bean id="userMapper" class="com.mapper.UserMapperImpi">
<property name="sqlSession" ref="sqlSession"/>
</bean>
6.测试使用即可
2.第二种继承SqlSessionDaoSupport
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-hOEWuLmb-1658999117413)(spring.assets/image-20220305192536465.png)]
public class UserMapperImpi2 extends SqlSessionDaoSupport implements UserMapper{
@Override
public List<User> selectUser() {
/* SqlSession sqlSession = getSqlSession();
UserMapper mapper = sqlSession.getMapper(UserMapper.class);
return mapper.selectUser();*/
return getSqlSession().getMapper(UserMapper.class).selectUser();
}
}
applicationcontext.xml
<!---->
<bean id="userMapper2" class="com.mapper.UserMapperImpi2">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
</bean>
12.声明式事务
什么是事务
事务ACID原则:
●原子性
●一致性
●隔离性
。多个业务可能操作同-个资源,防止数据损坏
●持久性
。事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中!
2.spring中的事务管理
●声明式事务: AOP
●编程式事务:需要再代码中,进行事务的管理
事务
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--结合AOP实现事务的织入-->
<!--配置事务的类-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--给那些方法配置事务-->
<!--配置事务的传播特性: I new propagation=-->
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<!--当前事务的所有类所有方法-->
<aop:pointcut id="txPointCut" expression="execution(* com.mapper.*.*(..))"/>
</aop:config>
<!--配置声明式事务-->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!--结合AOP实现事务的织入-->
<!--配置事务的类-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!--给那些方法配置事务-->
<!--配置事务的传播特性: I new propagation=-->
<tx:method name="add" propagation="REQUIRED"/>
<tx:method name="delete" propagation="REQUIRED"/>
<tx:method name="update" propagation="REQUIRED"/>
<tx:method name="query" read-only="true"/>
<tx:method name="*" propagation="REQUIRED"/>
</tx:attributes>
</tx:advice>
<!--配置事务切入-->
<aop:config>
<!--当前事务的所有类所有方法-->
<aop:pointcut id="txPointCut" expression="execution(* com.mapper.*.*(..))"/>
</aop:config>