Spring总结
Posted lyang-a
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring总结相关的知识,希望对你有一定的参考价值。
Spring
????SSH:Spring . Struts1/2 . Hiberernate
????SSM:Spring . SpringMVC . Mybatis
????Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。
???????◆目的:解决企业应用开发的复杂性
???????◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能
???????◆范围:任何Java应用
????Spring是一个轻量级**控制反转(IoC)和面向切面(AOP)**的容器框架。
起源
???要谈Spring的历史,就要先谈J2EE。J2EE应用程序的广泛实现是在1999年和2000年开始的,它的出现带来了诸如事务管理之类的核心中间层概念的标准化,但是在实践中并没有获得绝对的成功,因为开发效率,开发难度和实际的性能都令人失望。
??曾经使用过EJB开发JAVA EE应用的人,一定知道,在EJB开始的学习和应用非常的艰苦,很多东西都不能一下子就很容易的理解。EJB要严格地实现各种不同类型的接口,类似的或者重复的代码大量存在。而配置也是复杂和单调,同样使用JNDI进行对象查找的代码也是单调而枯燥。虽然有一些开发工作随着xdoclet的出现,而有所缓解,但是学习EJB的高昂代价,和极低的开发效率,极高的资源消耗,都造成了EJB的使用困难。而Spring出现的初衷就是为了解决类似的这些问题。
???Spring的一个最大的目的就是使JAVA EE开发更加容易。同时,Spring之所以与Struts、Hibernate等单层框架不同,是因为Spring致力于提供一个以统一的、高效的方式构造整个应用,并且可以将单层框架以最佳的组合揉和在一起建立一个连贯的体系。可以说Spring是一个提供了更完善开发环境的一个框架,可以为POJO(Plain Ordinary Java Object)对象提供企业级的服务。
???Spring的形成,最初来自Rod Jahnson所著的一本很有影响力的书籍《Expert One-on-One J2EE Design and Development》,就是在这本书中第一次出现了Spring的一些核心思想,该书出版于2002年。另外一本书《Expert One-on-One J2EE Development without EJB》,更进一步阐述了在不使用EJB开发JAVA EE企业级应用的一些设计思想和具体的做法。有时间了可以详细的研读一下。
Spring的初衷:
1、JAVA EE开发应该更加简单。
2、使用接口而不是使用类,是更好的编程习惯。Spring将使用接口的复杂度几乎降低到了零。
3、为JavaBean提供了一个更好的应用配置框架。
4、更多地强调面向对象的设计,而不是现行的技术如JAVA EE。
5、尽量减少不必要的异常捕捉。
6、使应用程序更加容易测试。
Spring的目标:
1、可以令人方便愉快的使用Spring。
2、应用程序代码并不依赖于Spring APIs。
3、Spring不和现有的解决方案竞争,而是致力于将它们融合在一起。
Spring的基本组成:
1、最完善的轻量级核心框架。
2、通用的事务管理抽象层。
3、JDBC抽象层。
4、集成了Toplink, Hibernate, JDO, and iBATIS SQL Maps。
5、AOP功能。
6、灵活的MVC Web应用框架。
Spring架构
推荐书籍:Spring in Action
J2EE三层结构的演变
package com.sxt.factory;
import java.io.InputStream;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
public class ObjectFactory {
/**
* ioc 容器
* key 类的全路径
* value 类的对象
*/
public static Map<String,Object> ioc = new HashMap<String,Object>();
/**
* @Title: getInstance
* @author: Mr.T
* @date: 2019年11月20日 上午10:54:28
* @Description:
* 这种方案不足 ,利用反射的灵活可以创建各种对象,减少工厂的个数.但是 效率堪忧.
* 发现效率低的原因,由于IOC容器没有对象,所以需要使用反射进行创建对象,再放入IOC容器.
* 如果,需要使用时,IOC容器存在需要使用的对象,那么效率不仅仅没有降低,且提高了.
* 当项目启动时,就直接将需要创建的对象,放入IOC容器中
* @param <T>
* @param cls
* @return
* @return: T
*/
public static <T> T getInstance(Class<T> cls) {
/**
* 每次创建对象都是创建新的对象
*/
T t = null;
// 获取类的全路径
String key = cls.getName();
// 判断对象容器中是否存在 若存在直接取
if(ioc.containsKey(key)) {
return (T) ioc.get(key);
}
// 若不存在 则创建一个,返回 ,且将对象放入到IOC容器中
try {
t = cls.newInstance();
ioc.put(key, t);
} catch (Exception e) {
e.printStackTrace();
}
return t;
}
public void init() {
InputStream in = ObjectFactory.class.getClassLoader().getResourceAsStream("obj.properties");
Properties prop = new Properties();
try {
prop.load(in);
String dao = prop.getProperty("dao");
String service = prop.getProperty("service");
String[] classes = dao.split(",");
for (int i = 0; i < classes.length; i++) {
Class<?> cls = Class.forName(classes[i]);
String name = cls.getName();
Object obj = cls.newInstance();
ioc.put(name, obj);
}
classes = service.split(",");
for (int i = 0; i < classes.length; i++) {
Class<?> cls = Class.forName(classes[i]);
String name = cls.getName();
Object obj = cls.newInstance();
ioc.put(name, obj);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
dao=com.sxt.dao.impl.UserDaoImpl,com.sxt.dao.impl.ClassesDaoImpl
service=com.sxt.service.impl.UserServiceImpl,com.sxt.service.impl.ClassesServiceImpl
Spring应用
???在实际开发中,对象和方法是最基础,最核心的东西.Spring核心只进行对象和方法的管理.对象的管理,在Spring中被称之为IOC/DI-控制反转(Inversion of Control,缩写为IoC).
IOC控制反转:
???将对象的创建初始化的权利,从开发者手中转移到Spring容器.由Spring将程序中需要的对象进行创建和装配.减少了开发者对对象的管理工作.这种模式就被称之为控制反转.
**DI—Dependency Injection,即“依赖注入”**:
-
IoC的别名,2004年,Martin Fowler探讨了同一个问题,既然IoC是控制反转,那么到底是“哪些方面的控制被反转了呢?”,经过详细地分析和论证后,他得出了答案:“获得依赖对象的过程被反转了”。控制被反转之后,获得依赖对象的过程由自身管理对象变为由IoC容器主动注入。于是,他给“控制反转”取了一个更合适的名字叫做“依赖注入(Dependency Injection,DI)”。他的这个答案,实际上给出了实现IoC的方法:注入。
-
所谓依赖注入,就是由IoC容器在运行期间,动态地将某种依赖关系注入到对象之中。
-
所以,依赖注入(DI)和控制反转(IoC)是从不同的角度描述的同一件事情,就是指通过引入IoC容器,利用依赖关系注入的方式,实现对象之间的解耦
Spring入门使用
??spring下载地址:https://repo.spring.io/webapp/#/artifacts/browse/tree/General/release
- 下载jar包
??Spring Framework 5.2.x: JDK 8-14
??Spring Framework 5.1.x: JDK 8-12
??Spring Framework 5.0.x: JDK 8-10
??Spring Framework 4.3.x: JDK 6-8
Spring各个jar包作用
??spring-aop:Spring的面向切面编程,提供AOP(面向切面编程)的实现
??spring-aspects:Spring提供的对AspectJ框架的整合
??spring-beans:Spring IOC的基础实现,包含访问配置文件、创建和管理bean等。
??spring-context:在基础IOC功能上提供扩展服务,此外还提供许多企业级服务的支持,有邮件服务、任务调度、JNDI定位,EJB集成、远程访问、缓存以及多种视图层框架的支持。
??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-messaging:消息支持相关包
??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框架相关的所有类。包含国际化、标签、Theme、视图展现的FreeMarker、JasperReports、 Tiles、Velocity、XSLT相关类。当然,如果你的应用使用了独立的MVC框架,则无需这个JAR文件里的任何类。
??spring-webmvc-portlet:Spring MVC的增强
??spring-websocket:提供 Socket通信, web端的推送功能
Spring的IOC配置
导入IOC相关jar包
spring-beans-4.3.24.RELEASE.jar
spring-context-4.3.24.RELEASE.jar
spring-context-support-4.3.24.RELEASE.jar
spring-core-4.3.24.RELEASE.jar
spring-expression-4.3.24.RELEASE.jar
日志包
commons-logging-1.2.jar
log4j-1.2.17.jar
log4j-api-2.11.2.jar
log4j-core-2.11.2.jar
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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 注册一个类的对象 -->
<bean id="user" class="com.sxt.bean.User" />
</beans>
测试程序
package com.sxt.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sxt.bean.User;
public class Test {
public static void main(String[] args) {
// 引入配置文件 读取配置信息
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
//new User()
// 此时使用 spring 容器 : 根据指定的类,就可以获取这个类的对象
// 说明容器中,本身就存在这个对象,那么一定有人创建了对象,创建人不是程序员,是Spring
// 此时 创建对象的权利,从开发者的手中,移交到Spring框架.这就是IOC (控制反转)
// 创建对象,控制对象的生命周期的角色发生反转,所以被称之为控制反转
// 从Spring IOC容器中获取对象
User bean = context.getBean(User.class);
// 使用对象调用方法
bean.study();
System.out.println(bean);
User bean2 = context.getBean(User.class);
System.out.println(bean2);
}
}
Spring创建对象的三种方式
方式一:构造方法
???使用构造器创建Bean对象,必须要有无参构造方法
<!--
id : bean标签唯一标识 也是对象唯一标识 一个bean只有一个ID值且整个IOC容器ID值不允许重复
name : bean标签中name属性,也是对象的name值,name值可以多个,使用逗号分隔.当name值没有时,id值就是name值
class : 需要创建对象的类
-->
<bean id="user" name="user1,user2,user3" class="com.sxt.bean.User" />
方式二:静态工厂
<!--
方式二: 使用静态工厂方式
class : 工厂类
factory-method : 工厂方法
-->
<bean id="userFactory" class="com.sxt.factory.UserFactory" factory-method="getUser"></bean>
package com.sxt.factory;
import com.sxt.bean.User;
public class UserFactory {
public static User getUser() {
return new User();
}
}
方式三:非静态工厂
<!--
方式三: 非静态工厂
factory-bean : 工厂对象
factory-method : 工厂方法
-->
<!-- 创建工厂对象,用于调用工厂中非静态的方法 -->
<bean id="userDyFactory" class="com.sxt.factory.UserDyFactory"></bean>
<!-- 根据工厂对象,工厂方法创建Bean对象 -->
<bean id="userBean" factory-bean="userDyFactory" factory-method="getUser"></bean>
package com.sxt.factory;
import com.sxt.bean.User;
public class UserDyFactory {
/**
* 非静态方法
*/
public User getUser() {
return new User();
}
}
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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
创建对象 : 无参构造方法
-->
<bean id="user1" class="com.sxt.bean.User"></bean>
<!-- 创建对象: 2个参数的构造方法 -->
<bean id="user2" class="com.sxt.bean.User">
<constructor-arg index="0" value="韩梅梅"></constructor-arg>
<constructor-arg index="1" value="女"></constructor-arg>
</bean>
<!-- 创建对象: 3个参数的构造方法 -->
<bean id="user3" class="com.sxt.bean.User">
<constructor-arg index="0" value="韩梅梅"></constructor-arg>
<constructor-arg index="1" value="女"></constructor-arg>
<constructor-arg index="2" value="18"></constructor-arg>
</bean>
<!-- 创建对象: 构造方法 参数名称注入属性值 -->
<bean id="user4" class="com.sxt.bean.User">
<constructor-arg name="name" value="韩梅梅"></constructor-arg>
<constructor-arg name="sex" value="女"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
</bean>
</beans>
package com.sxt.bean;
public class User {
// private String name;
// private String sex;
// private Integer age;
private String name1;
private String sex1;
private Integer age1;
public User() {
System.out.println("我是无参构造方法");
}
public User(String name, String sex) {
this.name1 = name;
this.sex1 = sex;
}
public User(String name, String sex, Integer age) {
this.name1 = name;
this.sex1 = sex;
this.age1 = age;
}
public void study() {
System.out.println("我是学习方法");
}
public String getName() {
return name1;
}
public void setName(String name) {
this.name1 = name;
}
public String getSex() {
return sex1;
}
public void setSex(String sex) {
this.sex1 = sex;
}
public Integer getAge() {
return age1;
}
public void setAge(Integer age) {
this.age1 = age;
}
@Override
public String toString() {
return "User [name=" + name1 + ", sex=" + sex1 + ", age=" + age1 + "]";
}
}
使用set方法注入属性值
<!--
方式二: 使用set方法注入属性
此时的name 值 不是真的类中属性名 只 set方法中setXxx中xxx
-->
<bean id="user5" class="com.sxt.bean.User">
<property name="name" value="韩梅梅"></property>
<property name="sex" value="女"></property>
<property name="age" value="18"></property>
</bean>
package com.sxt.bean;
public class User {
private String name1;
private String sex1;
private Integer age1;
public User() {
System.out.println("我是无参构造方法");
}
public User(String name, String sex) {
this.name1 = name;
this.sex1 = sex;
}
public User(String name, String sex, Integer age) {
this.name1 = name;
this.sex1 = sex;
this.age1 = age;
}
public void study() {
System.out.println("我是学习方法");
}
public String getName() {
return name1;
}
public void setName(String name) {
this.name1 = name;
}
public String getSex() {
return sex1;
}
public void setSex(String sex) {
this.sex1 = sex;
}
public Integer getAge() {
return age1;
}
public void setAge(Integer age) {
this.age1 = age;
}
@Override
public String toString() {
return "User [name=" + name1 + ", sex=" + sex1 + ", age=" + age1 + "]";
}
}
各种类型的属性注入
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
各种类型的属性的注入
-->
<!-- 1. 注入字符串 -->
<bean id="user1" class="com.sxt.bean.User">
<property name="str" value="我是字符串"></property>
</bean>
<!-- 2. 注入对象 方式一 -->
<bean id="st1" class="com.sxt.bean.Student">
<property name="name" value="韩梅梅"> </property>
<property name="sex" value="女"> </property>
</bean>
<!--
在注入属性值时,value 只能注入:基本数据类型和字符串,如果是对象,需要使用 ref 进行对相关联
-->
<bean id="user2" class="com.sxt.bean.User">
<property name="st" ref="st1" >
</property>
</bean>
<!-- 注入对象方式二 -->
<bean id="user3" class="com.sxt.bean.User">
<property name="st">
<bean class="com.sxt.bean.Student">
<property name="name" value="韩梅梅"> </property>
<property name="sex" value="女"> </property>
</bean>
</property>
</bean>
<!--3 .注入数组结构 -->
<bean id="user4" class="com.sxt.bean.User">
<property name="list1">
<array>
<value>韩梅梅</value>
<value>李磊</value>
<value>Jim</value>
<value>Lucy</value>
</array>
</property>
</bean>
<!-- list结构属性 -->
<bean id="user5" class="com.sxt.bean.User">
<property name="list1">
<list>
<value>韩梅梅</value>
<value>李磊</value>
<value>Jim</value>
<value>Lucy</value>
</list>
</property>
</bean>
<bean id="user6" class="com.sxt.bean.User">
<property name="list2">
<list>
<bean class="com.sxt.bean.Student">
<property name="name" value="韩梅梅"></property>
<property name="sex" value="女"></property>
</bean>
<bean class="com.sxt.bean.Student">
<property name="name" value="Lucy"></property>
<property name="sex" value="女"></property>
</bean>
<ref bean="st1"/>
</list>
</property>
</bean>
<!-- set结构属性 -->
<bean id="user7" class="com.sxt.bean.User">
<property name="set1">
<set>
<value>字符串1</value>
<value>字符串2</value>
<value>字符串3</value>
<value>字符串1</value>
<value>字符串1</value>
</set>
</property>
</bean>
<bean id="user8" class="com.sxt.bean.User">
<property name="set2">
<set>
<bean class="com.sxt.bean.Student">
<property name="name" value="韩梅梅"></property>
<property name="sex" value="女"></property>
</bean>
<bean class="com.sxt.bean.Student">
<property name="name" value="Lucy"></property>
<property name="sex" value="女"></property>
</bean>
<ref bean="st1"/>
</set>
</property>
</bean>
<!-- map结构 -->
<bean id="user9" class="com.sxt.bean.User">
<property name="map1">
<map>
<entry key="key1" value="value1"></entry>
<entry key="key2" value="value2"></entry>
<entry key="key3" value="value3"></entry>
<entry key="key4" value="value4"></entry>
</map>
</property>
</bean>
<bean id="user10" class="com.sxt.bean.User">
<property name="map2">
<map>
<entry key="key1" value-ref="st1"></entry>
<entry key="key2" >
<bean class="com.sxt.bean.Student">
<property name="name" value="韩梅梅"></property>
<property name="sex" value="女"></property>
</bean>
</entry>
</map>
</property>
</bean>
<!-- properties 对象 -->
<bean id="user11" class="com.sxt.bean.User">
<property name="prop">
<props>
<prop key="key1">value1</prop>
<prop key="key2">value2</prop>
<prop key="key3">value3</prop>
</props>
</property>
</bean>
</beans>
package com.sxt.bean;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
public class User {
private String str; // 字符串
private Student st; // 对象
private List<String> list1; //list集合
private List<Student> list2; //list集合
private Set<String> set1; //set集合
private Set<Student> set2; //set集合
private Map<String,String> map1; // Map
private Map<String,Student> map2; // Map
private Properties prop; // properties
public String getStr() {
return str;
}
public void setStr(String str) {
this.str = str;
}
public Student getSt() {
return st;
}
public void setSt(Student st) {
this.st = st;
}
public List<String> getList1() {
return list1;
}
public void setList1(List<String> list1) {
this.list1 = list1;
}
public List<Student> getList2() {
return list2;
}
public void setList2(List<Student> list2) {
this.list2 = list2;
}
public Set<String> getSet1() {
return set1;
}
public void setSet1(Set<String> set1) {
this.set1 = set1;
}
public Set<Student> getSet2() {
return set2;
}
public void setSet2(Set<Student> set2) {
this.set2 = set2;
}
public Map<String, String> getMap1() {
return map1;
}
public void setMap1(Map<String, String> map1) {
this.map1 = map1;
}
public Map<String, Student> getMap2() {
return map2;
}
public void setMap2(Map<String, Student> map2) {
this.map2 = map2;
}
public Properties getProp() {
return prop;
}
public void setProp(Properties prop) {
this.prop = prop;
}
}
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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--
注意:
在spring中,默认会根据配置文件创建对象放入到ioc容器中
lazy-init : 是否懒加载 default/false : 不进行懒加载 ,程序启动加载对象.true 进行懒加载,只有使用时才加载
scope : 对象作用域
singleton : 单例 默认
prototype : 非单例
request : 每次请求创建对象
session : 每次会话
init-method :
初始化方法 对象创建后进行对象初始化调用的方法
destroy-method :
ioc容器中,对象销毁时调用的方法
autowire :自动装配对象属性
byType : 根据类型装配
byName : 根据属性的name装配
autowire-candidate : 是否被自动装配查找
true : 可以被自动装配 默认
false : 不可以被自动装配
primary :
在装配时,推荐使用的
abstract : 是否是抽象类
parent : 父级,可以进行属性继承
depends-on : 依赖的Bean
-->
<bean id="user1" class="com.sxt.bean.User" scope="singleton" init-method="init" destroy-method="destory" depends-on="st" ></bean>
<bean id="st" class="com.sxt.bean.Student" autowire-candidate="default" >
<property name="name" value="韩梅梅"></property>
<property name="sex" value="18"></property>
</bean>
</beans>
spring改造web3层结构
pojo
package com.sxt.pojo;
public class User {
private String name;
private Integer age;
public User() {}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
@Override
public String toString() {
return "User [name=" + name + ", age=" + age + "]";
}
}
dao
package com.sxt.dao;
import java.util.List;
import com.sxt.pojo.User;
public interface IUserDao {
public List<User> selectAll();
}
dao.impl
package com.sxt.dao.impl;
import java.util.ArrayList;
import java.util.List;
import com.sxt.dao.IUserDao;
import com.sxt.pojo.User;
public class UserDaoImpl implements IUserDao{
@Override
public List<User> selectAll() {
System.out.println("dao 层 selectAll");
List<User> list = new ArrayList<User>();
list.add(new User("韩梅梅", 18));
list.add(new User("Lucy", 18));
list.add(new User("Lily", 18));
return list;
}
}
service
package com.sxt.service;
import java.util.List;
import com.sxt.pojo.User;
public interface IUserService {
public List<User> queryAll();
}
service.impl
package com.sxt.service.impl;
import java.util.List;
import com.sxt.dao.IUserDao;
import com.sxt.pojo.User;
import com.sxt.service.IUserService;
public class UserServiceImpl implements IUserService {
private IUserDao userDao;
@Override
public List<User> queryAll() {
return userDao.selectAll();
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
}
controller
package com.sxt.controller;
import java.util.List;
import com.sxt.pojo.User;
import com.sxt.service.IUserService;
public class UserController {
private IUserService userService;
public void list() {
List<User> users = userService.queryAll();
for (User user : users) {
System.out.println(user);
}
}
public void setUserService(IUserService userService) {
this.userService = userService;
}
}
配置文件:
<?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 http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 配置Dao 层 -->
<bean id="userDao" class="com.sxt.dao.impl.UserDaoImpl"></bean>
<!-- 配置Service -->
<bean id="userService" class="com.sxt.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao"></property>
</bean>
<!-- 配置controller -->
<bean id="userController" class="com.sxt.controller.UserController">
<property name="userService" ref="userService"></property>
</bean>
</beans>
测试类:
package com.sxt.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sxt.controller.UserController;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
UserController bean = context.getBean(UserController.class);
bean.list();
}
}
IOC相关注解
? 为了简化开发,Spring提供了一些内置注解:
? @Component:表示是一个组件,使用该注解修饰类,Spring自动为其创建对象,放入IOC容器
? @Service:继承于Component 注解,表示一个组件,主要用于Service层
? @Repository:继承于Component 注解,表示一个组件,主要用持久层
? @Controller:继承于Component 注解,表示一个组件,主要用于控制层
? @Autowired:用于为属性进行自动装配
? **@Qualifier(name)**:组件名称
导入jar包
spring-aop-4.3.24.RELEASE.jar
引入xml约束
aop约束
context约束
配置组件扫描
<?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"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://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:component-scan base-package="com.sxt.dao.impl,com.sxt.service.impl,com.sxt.controller"></context:component-scan>
<!-- 包下面所有的类都要进行扫描 -->
<!-- <context:component-scan base-package="com.sxt"></context:component-scan> -->
</beans>
AOP
AOP的概念
???Spring的IoC是管理对象,使用AOP管理方法。如何管理方法,扩展方法,如何扩展方法?方法中套方法,装饰者模式。
???但是装饰者模式,需要类与类之间存在关系.提高了程序耦合读,不便于维护和扩展.基于这个原因,开发者提出了AOP的想法,面向切面编程 ----- 横向扩展程序.这种扩展方式,也被称之为拔插式的扩展,需要使用时,只需要织入想要扩展的内容,不需要时,只需要取消织入. 具体的实现,依赖动态代理模式,相对于纵向扩展,编码的复杂度高一些,但是代码灵活一些。
场景
- 事务管理
??开启事务
??关闭事务
??回滚事务
- 日志采集
??将请求信息进行持久化.发生请求信息获得方式都一样,只需要将请求对象统一保存.数据分析.
JDK代理
???代理,代替打理。
静态代理
package com.sxt.target;
/**
* 被代替的类
*/
public class TargetClass {
public void sing() {
System.out.println(" 世上只有妈妈好 ");
}
}
package com.sxt.target;
/**
* 代理类
*/
public class ProxyClass {
// 被代理的对象
TargetClass targetClass;
public ProxyClass(TargetClass targetClass) {
super();
this.targetClass = targetClass;
}
public void sing() {
System.out.println("查看行程计划");
System.out.println("确定时间");
System.out.println("修改行程计划");
System.out.println("下周二");
targetClass.sing();
}
}
package com.sxt.target;
public class Test {
public static void main(String[] args) {
// 被代理的对象
TargetClass targetClass = new TargetClass();
// 创建代理类
ProxyClass proxyClass = new ProxyClass(targetClass);
//调用方法
proxyClass.sing();
}
}
静态代理的不足:
???必须定义代理类,且代理的方法声明了,扩展性相对较差.类和类之间产生了关系,耦合性加强了.不便于维护 ,代码的可读性也会降低。
动态代理
??动态的为需要代理的类,创建一个具体的代理类.不再需要开发者定义具体的代理的类.这种方式,就是动态代理.JDK为此制定了一个标准.
类: Proxy代理类,所有代理的类基类
???Proxy
提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类.
??newProxyInstance(ClassLoader loader, Class<?>... interfaces,InvocationHandler hanlder) : 类加载器 当前类的加载器,interfaces 接口的Class对象 hanlder 代理类的处理器
??接口:InvocationHandler 与代理类关联调用程序的处理器
配置类:
package com.sxt.target;
/**
* 配置类
*/
public class Config {
//开启事务的方法的名称的前缀
public static String[] preFix = {"add","update","delete"};
}
代理类处理器
package com.sxt.target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 代理类绑定的代理处理器
*/
public class ProxyHanlder implements InvocationHandler {
// 被代理的目标 此时类型时 Object 那么传入任何类型都可以
private Object proxyTarget;
public ProxyHanlder(Object proxyTarget) {
this.proxyTarget = proxyTarget;
}
/**
* proxy : ProxyHanlder 对象 代理处理器对象
* method : 被代理调用的方法
* args : 方法中参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
for (String name : Config.preFix) {
if(methodName.startsWith(name)) {
new TransctionManager().beginTrancation();
}
}
Object obj = method.invoke(proxyTarget, args);
for (String name : Config.preFix) {
if(methodName.startsWith(name)) {
new TransctionManager().commitTrancation();
}
}
return obj;
}
}
被代理目标类:
package com.sxt.target;
/**
* @ClassName: TargetClassInteterface
* @Description: 被代理的类的接口
* @author: Mr.T
* @date: 2019年11月22日 上午11:14:03
*/
public interface TargetClassInteterface {
public void addUser(String name) ;
public void deleteUser() ;
public void updateUser() ;
public void selectUser() ;
}
package com.sxt.target;
/**
* @ClassName: TargetClass
* @Description: 具体的代理类
* @author: Mr.T
* @date: 2019年11月22日 上午11:15:19
*/
public class TargetClass implements TargetClassInteterface {
@Override
public void addUser(String name) {
System.out.println("新增用户");
}
@Override
public void deleteUser() {
System.out.println("删除用户");
}
@Override
public void updateUser() {
System.out.println("修改用户");
}
@Override
public void selectUser() {
System.out.println("查询用户");
}
}
增强的内容:
package com.sxt.target;
/**
* @ClassName: TransctionManager
* @Description: 事务管理器 增强的具体内容
* @author: Mr.T
* @date: 2019年11月22日 上午11:35:37
*/
public class TransctionManager {
public void beginTrancation() {
System.out.println("开启事务");
}
public void commitTrancation() {
System.out.println("提交事务");
}
}
测试类:
package com.sxt.target;
import java.lang.reflect.Proxy;
public class Test {
public static void main(String[] args) {
// 生成代理编译后的文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// 创建了被代理的目标
TargetClassInteterface targetInterface = new TargetClass();
// 创建代理类的处理器
ProxyHanlder proxyHandler = new ProxyHanlder(targetInterface);
// 创建代理类
TargetClassInteterface proxyObj = (TargetClassInteterface) Proxy.newProxyInstance(Test.class.getClassLoader(), new Class[] {TargetClassInteterface.class}, proxyHandler);
proxyObj.addUser("user");
System.out.println("======================");
proxyObj.deleteUser();
System.out.println("======================");
proxyObj.updateUser();
System.out.println("======================");
proxyObj.selectUser();
System.out.println("======================");
}
}
不足:
- 必须依赖接口,具有一定局限性。
- 由于使用的反射,所以效率相对较低。
源码分析
package com.sun.proxy;
import com.sxt.target2.TargetClassInteterface;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
// 生成的代理类 $Proxy0 是 Proxy 子类且是 TargetClassInteterface 实现类
// 那么这个代理类就要有 TargetClassInteterface 里面抽象方法
public final class $Proxy0 extends Proxy implements TargetClassInteterface {
private static Method m0; // ======> Object类中的 hashCode
private static Method m1; // ======> Object类中的 equals
private static Method m2; // ======> Object类中的 toString
private static Method m3; // ======> 实现了接口中 addUser 方法
static
{
try {
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("com.sxt.target2.TargetClassInteterface").getMethod("addUser", new Class[] { Class.forName("java.lang.String") });
return;
}
catch (NoSuchMethodException localNoSuchMethodException) {
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException) {
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
// 创建代理类对象 InvocationHandler 对象 本质上就是传入 ProxyHanlder 自己定义的代理类程序处理器
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
// 调用父类的有参构造方法 : 将自己定义 ProxyHanlder 传给Proxy
super(paramInvocationHandler);
// 将自己定义的处理器 赋值给了 Proxy 类中 h 成员变量
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
// 在测试类中,使用创建出来的代理对象 调用 addUser ,其实就是调用此处的addUser
public final void addUser(String paramString)
throws
{
try
{
// this.h : ProxyHandler对象
// this.h 当前类中h变量 当前类中没有 h 所以h是从父类 Proxy类继承而来.
// this.h 就是父类Proxy中h,而Proxy中h ,是自定义的ProxyHandler
// proxyHandler.invoke(this,m3,paramString); //this : proxy 代理类对象 m3 具体的add方法 paramString 传入的参数
// 调用Proxy Handler的 invoke 方法
/*
// 被代理的目标 此时类型时 Object 那么传入任何类型都可以
private Object proxyTarget;
public ProxyHanlder(Object proxyTarget) {
this.proxyTarget = proxyTarget;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
beginTrancation(); // 开启事务
//m3 addUser.invoke(obj ,args ) : // 此时的obj :proxyTarget ----> 被代理的具体目标类对象 addUser(String name) { 新增用户 }
Object obj = method.invoke(proxyTarget, args);
commitTrancation();
return obj;
}
*/
this.h.invoke(this, m3, new Object[] { paramString });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
}
JDK动态代理的不足:
??结构相对复杂,必须依赖接口.被代理的对象要有接口(接口要当做参数传递).其二,其本质是使用的反射,执行效率相对而言较低.
由于以上原因,Cglib出现,解决以上问题.
Cglib动态代理
??问题1:必须要有接口,没有接口如何实现动态代理?
?????既然没有接口,那么使用子类,使用继承。
???问题2:利用反射执行效率低,如何解决效率低?
????执行效率低,创建对象,低在方法查找。那么将需要代理的方法创建好,存储在容器中,需要使用时,根据方法对应的索引,找到方法.。
Cglib使用
-
导入jar包
asm-7.0.jar cglib-3.2.10.jar
-
编写代码
目标类
package com.target;
/**
* 被代理的类
*/
public class TargetClass {
public void sing() {
System.out.println("唱歌");
}
}
增强类
package com.target;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 方法拦截器
*/
public class MyMethodIntercepter implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
before();
// obj : 子类对象 ----父类 TargetClass
// args : 参数
// cglib的动态代理 不是反射. 使用 索引找到该方法
Object rs = proxy.invokeSuper(obj, args);
after();
return rs;
}
public void before() {
System.out.println("前置增强");
}
public void after() {
System.out.println("后置增强");
}
}
创建代理类:
package com.target;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.proxy.Enhancer;
public class Test {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://java");
// 创建增强器
Enhancer enhancer = new Enhancer();
// 增强的目标
enhancer.setSuperclass(TargetClass.class);
// 使用谁增强
enhancer.setCallback(new MyMethodIntercepter());
// 创建代理类
TargetClass obj = (TargetClass) enhancer.create();
// 调用方法
obj.sing();
}
}
package com.target;
import java.lang.reflect.InvocationTargetException;
import net.sf.cglib.core.DebuggingClassWriter;
import net.sf.cglib.reflect.FastClass;
public class Test2 {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://java");
FastClass create = FastClass.create(TargetClass.class);
//获取方法的索引
int index = create.getIndex("sing", new Class[] {});
//调用方法
try {
create.invoke(index, new TargetClass(), null);
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
Cglib动态代理的不足
- 由于Cglib使用继承,所以无法代理final修饰类
- 也无法代理final修饰的方法
spring-Aop 配置方式一
-
导入jar包
aspectjweaver.jar commons-logging-1.2.jar log4j-1.2.17.jar log4j-api-2.11.2.jar log4j-core-2.11.2.jar spring-aspects-4.3.24.RELEASE.jar spring-beans-4.3.24.RELEASE.jar spring-context-4.3.24.RELEASE.jar spring-context-support-4.3.24.RELEASE.jar spring-core-4.3.24.RELEASE.jar spring-expression-4.3.24.RELEASE.jar
-
编写代码
被增强的目标
package com.sxt.target;
/**
* 目标类接口
*/
public interface ITargetClass {
/**
* 唱歌方法
*/
public void sing();
}
package com.sxt.target.impl;
import com.sxt.target.ITargetClass;
public class TargetClassImpl implements ITargetClass{
@Override
public void sing() {
int m = 0;
System.out.println(1/m);
System.out.println(" 月亮代表我的心 ");
}
}
增强类:
package com.sxt.advice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
public class BeforeAdvice implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("前置增强");
}
}
package com.sxt.advice;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
/**
* 后置增强类
*/
public class AfterAdvice implements AfterReturningAdvice{
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("后置增强");
}
}
package com.sxt.advice;
import java.lang.reflect.Method;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
* 环绕增强
*/
public class RoundAdvice implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
//调用前置增强
beforeAdvice();
//目标方法执行
Method method = invocation.getMethod(); //目标方法
Object[] arguments = invocation.getArguments(); //目标方法的参数
//执行当前目标方法
Object rs = invocation.proceed();
afterAdvice();
return rs;
}
public void beforeAdvice() {
System.out.println("前置增强");
}
public void afterAdvice() {
System.out.println("后置增强");
}
}
package com.sxt.advice;
import org.springframework.aop.ThrowsAdvice;
public class ExceptionAdvice implements ThrowsAdvice{
/**
* 方法名必须为afterThrowing 且要有 Throwable 参数
*/
public void afterThrowing(Throwable th) {
System.out.println("我是异常增强,发生异常时我执行");
}
}
aop配置
<?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 http://www.springframework.org/schema/beans/spring-beans-3.2.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">
<!-- 配置增强的目标 -->
<bean id="targetClass" class="com.sxt.target.impl.TargetClassImpl"></bean>
<!-- 具体增强类对象 -->
<!-- 前置增强 -->
<bean id="beforeAdvice" class="com.sxt.advice.BeforeAdvice"></bean>
<!-- 后置增强 -->
<bean id="afterAdvice" class="com.sxt.advice.AfterAdvice"></bean>
<!-- 环绕增强 -->
<bean id="roundAdvice" class="com.sxt.advice.RoundAdvice"></bean>
<!-- 异常增强 -->
<bean id="exceptionAdvice" class="com.sxt.advice.ExceptionAdvice"></bean>
<!-- 织入: 将切点 和 具体增强类结合 -->
<!-- 进行AOP配置 -->
<aop:config>
<!-- 配置切入点 : 需要增强的方法 -->
<aop:pointcut expression="execution(* com.sxt.target.impl.TargetClassImpl.*(..))" id="pointcut" />
<!-- 配置切面方法 -->
<!-- <aop:advisor advice-ref="beforeAdvice" pointcut-ref="pointcut"/> -->
<!-- <aop:advisor advice-ref="afterAdvice" pointcut-ref="pointcut"/> -->
<!-- <aop:advisor advice-ref="roundAdvice" pointcut-ref="pointcut"/> -->
<aop:advisor advice-ref="exceptionAdvice" pointcut-ref="pointcut" />
</aop:config>
</beans>
测试:
package com.sxt.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.sxt.target.ITargetClass;
public class Test {
public static void main(String[] args) {
ApplicationContext context = new ClassPathXmlApplicationContext("application.xml");
ITargetClass obj = (ITargetClass) context.getBean("targetClass");
obj.sing();
}
}
Spring-Aop 配置方式二
? AspectJ是一个基于Java语言的AOP框架,Spring2.0开始引入对AspectJ的支持,AspectJ扩展了Java语言,提供了专门的编译器,在编译时提供了横向代码的注入。
? @AspectJ是AspectJ1.5新增功能,通过JDK1.5注解技术,允许直接在Bean中定义切面
? 新版本的Spring中,建议使用AspectJ方式开发AOP
编写目标类:
package com.sxt.target;
/**
* 目标类接口
*/
public interface ITargetClass {
/**
* 唱歌方法
*/
public void sing();
}
package com.sxt.target.impl;
import com.sxt.exception.MyException;
import com.sxt.target.ITargetClass;
public class TargetClassImpl implements ITargetClass{
@Override
public void sing() {
throw new MyException("4001001", "自己定义的异常");
// System.out.println("");
}
}
增强类:
package com.sxt.advice;
import org.aspectj.lang.ProceedingJoinPoint;
import com.sxt.exception.MyException;
/**
* 增强类
*/
public class MyAdvice {
public void beforeAdvice() {
System.out.println("前置增强");
}
public void afterAdvice() {
System.out.println("后置增强");
}
public void roundAdvice(ProceedingJoinPoint pjp) {
beforeAdvice();
// 获取参数
Object[] args = pjp.getArgs();
// 增强的目标方法
Object target = pjp.getTarget();
try {
Object proceed = pjp.proceed();
afterAdvice();
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* 可以做异常拦截
*/
public void exceptionAdvice(Throwable tx) {
if (tx instanceof MyException) {
MyException myException = (MyException) tx;
System.out.println(myException.getCode());
System.out.println(myException.getMsg());
return;
}
System.out.println(tx);
System.out.println("异常增强");
}
}
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 http://www.springframework.org/schema/beans/spring-beans-3.2.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">
<!-- 配置增强的目标 -->
<bean id="targetClass" class="com.sxt.target.impl.TargetClassImpl"></bean>
<!-- 具体增强类对象 -->
<bean id="myAdvice" class="com.sxt.advice.MyAdvice"></bean>
<!--
织入: 将切点 和 具体增强类结合
-->
<!-- 进行AOP配置 -->
<aop:config>
<!-- 配置增强对象 -->
<aop:aspect ref="myAdvice">
<!-- 配置切入点 -->
<aop:pointcut expression="execution(* com.sxt.target.impl.*.*(..))" id="pointcut"/>
<!-- 配置增强对象中方法 前置增强 -->
<!-- <aop:before method="beforeAdvice" pointcut-ref="pointcut" /> -->
<!-- 后置增强 -->
<!-- <aop:after method="afterAdvice" pointcut-ref="pointcut"/> -->
<!-- 环绕增强 -->
<!-- <aop:around method="roundAdvice" pointcut-ref="pointcut"/> -->
<!-- 异常增强 -->
<aop:after-throwing method="exceptionAdvice" pointcut-ref="pointcut" throwing="tx"/>
</aop:aspect>
</aop:config>
</beans>
Spring-Aop 配置方式:注解
增强类:
package com.sxt.advice;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import com.sxt.exception.MyException;
/**
* 增强类
*/
@Component
@Aspect
public class MyAdvice {
// @Before("execution(* com.sxt.target.impl.*.*(..))")
public void beforeAdvice() {
System.out.println(this);
System.out.println("前置增强");
}
/**
* @AfterReturning 可以拿到 目标方法的返回值
* @After 只能后置增强的效果
*/
@AfterReturning(value="execution(* com.sxt.target.impl.*.*(..))",returning = "rs")
public void afterAdvice(Object rs) {
System.out.println(rs);
System.out.println("后置增强");
}
// execution(* 包名.类.方法(..) ..:表示任意参数
// @Around("execution(* com.sxt.target.impl.*.*(..))")
public void roundAdvice(ProceedingJoinPoint pjp) {
beforeAdvice();
// 获取参数
Object[] args = pjp.getArgs();
// 增强的目标方法
Object target = pjp.getTarget();
try {
Object proceed = pjp.proceed();
//afterAdvice();
} catch (Throwable e) {
e.printStackTrace();
}
}
/**
* 可以做异常拦截
*/
// @AfterThrowing( value="execution(* com.sxt.target.impl.*.*(..))",throwing = "tx")
public void exceptionAdvice(Throwable tx) {
if(tx instanceof MyException) {
MyException myException = (MyException) tx;
System.out.println(myException.getCode());
System.out.println(myException.getMsg());
return ;
}
System.out.println(tx);
System.out.println("异常增强");
}
}
目标类:
package com.sxt.target.impl;
import org.springframework.stereotype.Component;
import com.sxt.exception.MyException;
import com.sxt.target.IUserDao;
@Component
public class UserDaoImpl implements IUserDao {
@Override
public int sing() {
//throw new MyException("4001001", "自己定义的异常");
System.out.println(" 月亮代表我的心 ");
return 10;
}
}
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:component-scan base-package="com.sxt"></context:component-scan>
<!-- 开启注解式 增强的通知
proxy-target-class 使用cglib 创建代理对象
1. UserDao 创建代理对象
2. 增强类绑定
默认是JDK 的代理动态代理 === UserDaoImpl 代理类
-->
<aop:aspectj-autoproxy proxy-target-class="true" ></aop:aspectj-autoproxy>
</beans>
总结
IoC/DI和AOP
IoC : 控制反转
??对于整个应用而言,创建对象的权利,从应用自身创建移交给了Spring容器.对象的创建的权利发生转向.所以被称之为控制反转.
DI : 依赖注入
??在研究控制反转时,发现其实反转的内容主要只,对象创建和对象注入.且对象的创建存在依赖关系.所以,控制反转其实更具体就是注入对象.所以被称之为DI.
??控制反转和依赖注入本质上一样的,但是角度不同.站在应用的角度,是控制反转,站在Spring容器的角度上,是依赖注入.
创建对象
创建对象的方式:
- 构造方法(默认方式)
- 静态工厂:通过静态方法创建对象
- 非静态工厂:非静态方法创建对象
- 注解
属性注入:
-
构造方法
-
set方法
-
注解
常用的注入方式:
??使用set方法注入: 因为set方法可以根据需要的属性进行注入,而构造方法依赖构造器.必须要有set方法.
??注解(最常用),一般只能用于自己定义的代码.在源码中无法使用注解.
IOC常用注解:
??@Component : 组件 被该注解注释的类, 会创建对象对象放入到IOC容器
??@Controller : 表示控制层 被该注解注释的类, 会创建对象对象放入到IOC容器
??@Service : 表示Service 层 被该注解注释的类, 会创建对象对象放入到IOC容器
??@Repository : 表示持久化层 被该注解注释的类, 会创建对象对象放入到IOC容器
??@Autowired : 自动装配 默认type装配
??@Qualifier(名称) : 使用指定的名称装配对象
注意:
???标准化.
???标准化,在开发中,在流程上会结构清晰,条理分明.代码可读性提高了.
??在维护上,定位问题相对快准确,扩展程序相对轻松
以上是关于Spring总结的主要内容,如果未能解决你的问题,请参考以下文章
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段
初识Spring源码 -- doResolveDependency | findAutowireCandidates | @Order@Priority调用排序 | @Autowired注入(代码片段
Spring boot:thymeleaf 没有正确渲染片段
What's the difference between @Component, @Repository & @Service annotations in Spring?(代码片段