在IOC(控制反转)中我们不需要new对象,由Spring来创建对象,主要通过在beans.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" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd"> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <bean id="..." class="..."> <!-- collaborators and configuration for this bean go here --> </bean> <!-- more bean definitions go here --> </beans>id和class的作用:
2.1 该id属性是标识单个bean定义的字符串;
2.2 该class属于bean的类型,并且使用完全限定类名;
实例:
<?xml version="1.0" encoding="UTF-8"?> <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"> <bean id="MybatisDaoImpl" class="com.muzi.Dao.MybatisDaoImpl"/> <bean id="OrealDaoImpl" class="com.muzi.Dao.OrealDaoImpl"/> <bean id="UserServiceImpl" class="com.muzi.Service.UserServiceImpl"> <property name="userDao" ref="OrealDaoImpl"/> </bean> </beans>注:在beans.xml中我们只需其,就可以实现对数据的调用。完全实现了对控制的反转且property为属性
注:value为具体的值,基本的数据类型——ref为引用spring容器中创建好的对象
我们创建实体类的时候,需要构造无参(默认存在)、有参以及get、set方法;
在beans.xml中实现对其配置bean定义对应于组成应用程序的实际对象。通常,您定义服务层对象,数据访问对象(DAO),表示对象(例如Struts Action实例),基础结构对象(例如Hibernate SessionFactories,JMS Queues等。只需要在xml中为其注入依赖,就可以在测试类中使用;
实例化对象的使用,ApplicationContext context = new ClassPathXmlApplicationContext(“services.xml”, “daos.xml”);其中可以放置一个或多个.xml的beans文件;通过context来实现对方法的调用;
注:只需要将服务层、Dao(数据访问对象)、表示对象基础结构对象注入到依赖中就可以在测试中实现
使用下标创建
<bean id="User" class="com.muzi.pojo.User"> <constructor-arg index="0" value="好好学Java"/> </bean>使用类型创建
<bean id="User" class="com.muzi.pojo.User"> <constructor-arg type="java.lang.String" value="萨达萨达"/> </bean>注:使用类型创建时Type的值是固定g
使用参数名来设置(使用最多的)
<bean id="User" class="com.muzi.pojo.User"> <constructor-arg name="uname" value="小木木"/> </bean>在依赖注入中有\ \ \ 等;
其中map注入于其他注入的区别
<property name="card"> <map> <entry key="身份证" value="145252252525236523"/> <entry key="银行卡" value="458523962563256352"/> <entry key="学生证" value="1253652698"/> </map> </property>map在实体中有关键字和value值;而其他的注入中没有;
其他注入list/array
<property name="books"> <array> <value>《西游记》</value> <value>《水浒传》</value> <value>《红楼梦》</value> <value>《三国志》</value> </array> </property> <property name="hobbys"> <list> <value>听歌</value> <value>敲代码</value> <value>兜风</value> </list> </property>注:其中为null的也是注入的标签
<property name="wife"> <null/> </property>自定义的输入,也是具有关键字
<property name="info"> <props> <prop key="性别">女</prop> <prop key="自评">我是一个爱好学习的人</prop> </props> </property>5.测试结果
Student{name='木子', address=Address{address='山西太原'}, hobbys=[听歌, 敲代码, 兜风], games=[lol, coc, qaq], card={身份证=145252252525236523, 银行卡=458523962563256352, 学生证=1253652698}, books=[《西游记》, 《水浒传》, 《红楼梦》, 《三国志》], wife='null', info={性别=女, 自评=我是一个爱好学习的人}}注:在使用p空间和c空间时,需要导入xml约束,不能直接使用
xmlns:p="http://www.springframework.org/schema/p" xmlns:c="http://www.springframework.org/schema/c"使用P空间注入信息
<bean id="User" class="com.muzi.pojo.User" p:name="桃夭" p:age="18"/>使用C空间注入信息
<!--在使用c空间注入信息时,需要在实体类中有构造方法Construct--> <bean id="User2" class="com.muzi.pojo.User" c:name="柳公子" c:age="20"/>(Spring的默认机制)
概念:singleton(单例):只有一个共享的实例存在,所有对这个bean的请求都会返回这个唯一的实例。
<bean id="hi" class="com.test.Hi" init-method="init" scope="singleton"> 1. ApplicationContext context = new FileSystemXmlApplicationContext("applicationContext.xml"); 2 Hi hi1 = (Hi) context.getBean("hi"); 3 Hi hi2 = (Hi) context.getBean("hi"); 4 System.out.println(hi1); 5 System.out.println(hi2);只有一个共享实例存在,只对一个bean返回实例;
二者的值一样;true
概念:prototype(多例):对这个bean的每次请求都会创建一个新的bean实例,类似于new 对象。
<bean id="hi" class="com.test.Hi" init-method="init" scope="prototype">二者的值不一样;false;
其余的requerst、session、application这些只能在web中使用;
使用注解需要条件:
导入约束:
<?xml version="1.0" encoding="UTF-8"?>- ==配置注解的支持:== ```xml <context:annotation-config/>
@AutoWire
通过class来实现注解的注入
【通常】可以直接在属性上使用;也可以在set方法上使用;
@Nullable与@Autowired(required = false))作用相同,都是可以使属性的值为空;且@Nullable可以设置在有参构造方法;
public People(@Nullable String name) { this.name = name; }当属性名和bean中的注入id名不一致时,可是联合使用@Qualifier(value = “id名”)与@AutoWire来实现;给予他指定的id名;
@Autowired @Qualifier(value = "cat22") private Cat cat; @Autowired @Qualifier(value = "dog12") private Dog dog;@Resouce
在使用的时候先查询id的name在去查询class,当属性和注入名不一样时,则通过bytype实现;二者都实现不了则报错;
@resource(name=“xxx”)指定id名
@Resource(name = "cat22") <bean id="cat22" class="com.muzi.pojo.Cat"/>@Component—组件放在实体类中,被spring管理,其作用相当于;
@Component //component就相当于在xml文件中所配置<bean id="user" class="com.muzi.pojo.user"> public class User { public String name; }@Value(“值”),注入值为属性使用注解
public class User { @Value("诸葛研") //相当于<bean id="user" class="com.muzi.pojo.user"> // <property name="name" value="诸葛研"> // </bean> public String name; }这四个注解的功能相同,都是将类注入到spring中,装备bean
注解@scope设置作用域单例(single)还是原型(prototype)
@Scope("single") //或是prototype public class User { class="com.muzi.pojo.user"> public String name; }xml与注解:
xml比较万能,能适用于任何场合;注解只能在自己的类中使用,维护想对复杂;xml与注解的最佳实现:
xml控制bean;
注解只管属性的注入;
==注:==要使注解生效,必须要开启注解支持;
<!--启动注解配置--> <context:annotation-config/> <!--扫描注解的下的包--> <context:component-scan base-package="com.muzi"/>==注:==容器中获取的配置类的class获取UserConfig.class;getbean获取的是方法名;
代理模式的好处:
可以使真实角色的操作更加纯粹,不用去关注一些公共的业务;公共业务交给代理角色,实现业务的分工;公共业务发生扩展的时候,方便管理;缺点:
当真实角色增加时,代理角色也会增加,会增加代码量;开发效率变低;InvocationHandler:由代理实例处理程序实现的接口;实现类时他会调用里面的程序方法invoke;
Objectinvoke(Object proxy, 方法 method, Object[] args) 处理代理实例上的方法调用并返回结果。Proxy:提供创建动态代理类和实例的静态方法,他也是由这些方法创建的所有动态代理类的超类;
动态代理分为两大类:基于接口的动态代理和基于类的动态代理;
基于接口——JDK动态代理基于类——cglib (高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口)java字节码实现——javasist动态代理的好处:
可以使真实角色的操作更加纯粹,不用去关注一些公共的业务;公共业务交给代理角色,实现业务的分工;公共业务发生扩展的时候,方便管理;一个动态代理类代理的是一个接口,对应的就是一类业务;代理的类
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class ProxyInvocationHandler implements InvocationHandler { //被代理接口 private Object tager; public void setTager(Object tager) { this.tager = tager; } //生成得到代理类 //this.getClass().getClassLoader()获得本地类 //tager.getClass().getInterfaces()获得本地类接口 public Object getproxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),tager.getClass().getInterfaces(),this); } //处理代理实类,并返回结果 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object invoke = method.invoke(tager); //调取该方法名字 log(method.getName()); return invoke; } //添加其他方法 public void log(String msg){ System.out.println("【debug】使用了"+msg+"方法"); } }测试
public class Client { public static void main(String[] args) { //真实角色 UserServiceImpl userService = new UserServiceImpl(); //代理角色 ProxyInvocationHandler pih = new ProxyInvocationHandler(); //实体类方法 pih.setTager(userService); //代理类 UserService proxy = (UserService) pih.getproxy(); proxy.add(); proxy.select(); } }原生的API接口实现
aop支持的依赖
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>使用aop的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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--注册bean--> <bean id="userService" class="com.muzi.Service.UserServiceImp"/> <bean id="afterLog" class="com.muzi.Log.AfterLog"/> <bean id="beforeLog" class="com.muzi.Log.BeforeLog"/> <!--方法1:使用原生的API接口--> <!--配置aop:需导入aop约束--> <aop:config> <!--切入点 id为名称 expression为表达式 execution为要执行的位置--> <aop:pointcut id="pointcut" expression="execution(* com.muzi.Service.UserServiceImp.*(..))"/> <!--执行环绕增加--> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/> </aop:config>测试实现
public class MyTest { @Test public void Test1(){ ApplicationContext context = new ClassPathXmlApplicationContext("Application.xml"); //动态代理代理的是接口 UserService userService = context.getBean("userService", UserService.class); userService.delete(); } }使用自定义方法实现——利用切面
自定义类——方法
public class diy { public void before(){ System.out.println("====方法执行前===="); } public void after(){ System.out.println("===方法执行后===="); } }2.切面和切点的引入
<?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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--注册bean--> <bean id="userService" class="com.muzi.Service.UserServiceImp"/> <bean id="afterLog" class="com.muzi.Log.AfterLog"/> <bean id="beforeLog" class="com.muzi.Log.BeforeLog"/> <!--方法二DIY--> <bean id="diy" class="com.muzi.Diy.diy"/> <aop:config> <!--切面 自定义ref是引用的类--> <aop:aspect ref="diy"> <!--切入点--> <aop:pointcut id="pointcut" expression="execution(* com.muzi.Service.UserServiceImp.*(..))"/> <!--通知--> <aop:before method="after" pointcut-ref="pointcut"/> <aop:after method="after" pointcut-ref="pointcut"/> </aop:aspect> </aop:config> </beans>使用注解式实现aop
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" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd"> <!--注解支持--> <context:annotation-config/> <!--扫描指定的包--> <context:component-scan base-package="com.muzi"/> <!--开启aop注解支持--> <aop:aspectj-autoproxy/> </beans>注解实现自定义类
package com.muzi.Diy; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.*; import org.springframework.context.annotation.Configuration; import org.springframework.stereotype.Component; @Configuration @Aspect @Component public class AnnotationPointcut { @Before("execution(* com.muzi.Service.UserServiceImp.*(..))") public void before(){ System.out.println("====方法执行前===="); } @After("execution(* com.muzi.Service.UserServiceImp.*(..))") public void after(){ System.out.println("===方法执行之后==="); } //环绕增强中,我们可以给定参数,代表我们要处理切入的点 @Around("execution(* com.muzi.Service.UserServiceImp.*(..))") public void around(ProceedingJoinPoint jp) throws Throwable { System.out.println("环绕前"); //获得签名 Signature signature = jp.getSignature(); System.out.println(signature+"signature"); //执行方法 Object proceed = jp.proceed(); System.out.println("环绕后"); } } 测试结果[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-DZqMtvIw-1599125270315)(C:\Users\暴走小萝莉\AppData\Roaming\Typora\typora-user-images\image-20200630161025872.png)]
接口
public interface UserMapper { List<User> getAll(); /*接口的方法名必须与映射的id名一致*/ User getByidUser(int id); }映射文件
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.muzi.Mapper.UserMapper"> <select id="getAll" resultType="user"> select * from user ; </select> <!--映射语句下的id必须与接口的方法名一致--> <select id="getByidUser" resultType="user" parameterType="int"> select * from mybatis.user where id=#{id}; </select> </mapper>实现类
public class UserMapperImp implements UserMapper { private SqlSessionTemplate sqlSession; /*原来都使用sqlsession 现在使用SqlSessionTemplate去实现*/ public void setSqlSession(SqlSessionTemplate sqlSession) { this.sqlSession = sqlSession; } /*想要实现哪个方法直接实现就好*/ public List<User> getAll() { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.getAll(); } public User getByidUser(int id) { UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.getByidUser(id); } }Mybatis-Config.xml配置
<?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN" "http://mybatis.org/dtd/mybatis-3-config.dtd"> <configuration> <typeAliases> <package name="com.muzi.pojo"/> </typeAliases> </configuration> <!-- <settings> <setting name="logImpl" value="STDOUT_LOGGING"/> </settings--> <!--使用typeAliases可以给实体类别名--> <!-- <typeAliases> <!– <typeAlias type="com.muzi.entity.User" alias="User"/>–> <!–使用package扫描包名,但没注解的话 只能使用类的小写为别名(大小写均可)–> <package name="com.muzi.pojo"/> </typeAliases>-->Mybatis-Sping.xml 配置
SqlSessionFactory
SqlSessionTemplate
注:需要导入Spring配置的文件
<?xml version="1.0" encoding="UTF-8"?> <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"> <!--dataSource 使用spring数据源替换mybatis配置 c3p0\dbcp\druid class使用spring提供的jbdc DriverManagerDataSource驱动管理数据源--> <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/mybatis?useSSL=true&useUnicode=true&characterEncoding=UTF-8"/> <property name="username" value="root"/> <property name="password" value="root"/> </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/muzi/Mapper/*.xml"/> </bean> <!--SqlSessionTemplate:就是SqlSession我们使用的--> <bean id="sqlSession" class="org.mybatis.spring.SqlSessionTemplate"> <constructor-arg index="0" ref="sqlSessionFactory"/> <!--只能使用构造器注入sqlSessionFactory没有set方法--> </bean> 注册实现类 <bean id="userMapper" class="com.muzi.Mapper.UserMapperImp"> <property name="sqlSession" ref="sqlSession"/> </bean> </beans>使用SqlSessionDaoSupport支持实现
实现类配置
public class UserMapperImp2 extends SqlSessionDaoSupport implements UserMapper { public List<User> getAll() { /*UserMapper mapper = sqlSession.getMapper(UserMapper.class); return mapper.getAll();*/ return getSqlSession().getMapper(UserMapper.class).getAll(); } public User getByidUser(int id) { return getSqlSession().getMapper(UserMapper.class).getByidUser(id); } }调用getSqlSession方法可以得到SqlSessionTemplate,后执行sql语句;注入的name为工厂
<bean id="userMapper2" class="com.muzi.Mapper.UserMapperImp2"> <property name="sqlSessionFactory" ref="sqlSessionFactory"/> </ben>事务要么都成功,要么都失败
acid原则:
A——原子性:事务是否完整的完成;C——一致性:事务在系统完整性中实施一致性;I——隔离性:多个业务操作同一个资源,防止数据损坏;D——持久性:事务被提交,就会被永久存储,结果都不会被影响;13.1 声明式事务(使用AOP切入)
在Spring—Dao.xml的配置
<!--配置声明式事务--> <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager"> <constructor-arg ref="dataSource" /> </bean> <!--结合aop实现事物的织入--> <!--配置事务通知--> <tx:advice id="txAdvice" transaction-manager="transactionManager"> <tx:attributes> <!--配置事务传播特性 propagation--> <tx:method name="insert"/> <tx:method name="select" propagation="REQUIRED"/> <tx:method name="*"/> </tx:attributes> </tx:advice> <!--配置事务切入点--> <aop:config> <!--mapper下面的所有类,所有方法--> <aop:pointcut id="txPoincut" expression="execution(* com.muzi.Mapper.*.*(..))"/> <aop:advisor advice-ref="txAdvice" pointcut-ref="txPoincut"/> </aop:config>13.2 编辑式事务
使用 @Autowired 注解进行装配,只能是根据类型进行匹配。@Autowired 注解可以用于 Setter 方法、构造函数、字段,甚至普通方法,前提是方法必须有至少一个参数。@Autowired 可以用于数组和使用泛型的集合类型。然后 Spring 会将容器中所有类型符合的 Bean 注入进来。@Autowired 标注作用于 Map 类型时,如果 Map 的 key 为 String 类型,则 Spring 会将容器中所有类型符合 Map 的 value 对应的类型的 Bean 增加进来,用 Bean 的 id 或 name 作为 Map 的 key。
@Autowired 标注作用于普通方法时,会产生一个副作用,就是在容器初始化该 Bean 实例的时候就会调用该方法。当然,前提是执行了自动装配,对于不满足装配条件的情况,该方法也不会被执行。
当标注了 @Autowired 后,自动注入不能满足,则会抛出异常。我们可以给 @Autowired 标注增加一个 required=false 属性,以改变这个行为。另外,每一个类中只能有一个构造函数的 @Autowired.required() 属性为 true。否则就出问题了。如果用 @Autowired 同时标注了多个构造函数,那么,Spring 将采用贪心算法匹配构造函数 ( 构造函数最长 )。
@Autowired 还有一个作用就是,如果将其标注在 BeanFactory 类型、ApplicationContext 类型、ResourceLoader 类型、ApplicationEventPublisher 类型、MessageSource 类型上,那么 Spring 会自动注入这些实现类的实例,不需要额外的操作。
当容器中存在多个 Bean 的类型与需要注入的相同时,注入将不能执行,我们可以给 @Autowired 增加一个候选值,做法是在 @Autowired 后面增加一个 @Qualifier 标注,提供一个 String 类型的值作为候选的 Bean 的名字。
Mapper..(…))"/> <aop:advisor advice-ref=“txAdvice” pointcut-ref=“txPoincut”/> </aop:config>
13.2 编辑式事务 ### 使用 @Autowired 和 @Qualifier 注解执行自动装配 使用 @Autowired 注解进行装配,只能是根据类型进行匹配。@Autowired 注解可以用于 Setter 方法、构造函数、字段,甚至普通方法,前提是方法必须有至少一个参数。@Autowired 可以用于数组和使用泛型的集合类型。然后 Spring 会将容器中所有类型符合的 Bean 注入进来。@Autowired 标注作用于 Map 类型时,如果 Map 的 key 为 String 类型,则 Spring 会将容器中所有类型符合 Map 的 value 对应的类型的 Bean 增加进来,用 Bean 的 id 或 name 作为 Map 的 key。 @Autowired 标注作用于普通方法时,会产生一个副作用,就是在容器初始化该 Bean 实例的时候就会调用该方法。当然,前提是执行了自动装配,对于不满足装配条件的情况,该方法也不会被执行。 当标注了 @Autowired 后,自动注入不能满足,则会抛出异常。我们可以给 @Autowired 标注增加一个 required=false 属性,以改变这个行为。另外,每一个类中只能有一个构造函数的 @Autowired.required() 属性为 true。否则就出问题了。如果用 @Autowired 同时标注了多个构造函数,那么,Spring 将采用贪心算法匹配构造函数 ( 构造函数最长 )。 @Autowired 还有一个作用就是,如果将其标注在 BeanFactory 类型、ApplicationContext 类型、ResourceLoader 类型、ApplicationEventPublisher 类型、MessageSource 类型上,那么 Spring 会自动注入这些实现类的实例,不需要额外的操作。 当容器中存在多个 Bean 的类型与需要注入的相同时,注入将不能执行,我们可以给 @Autowired 增加一个候选值,做法是在 @Autowired 后面增加一个 @Qualifier 标注,提供一个 String 类型的值作为候选的 Bean 的名字。 ###### TomCat控制台乱码问题:-Dfile.encoding=UTF-8