序文
ssmフレームワークの学習を終えたばかりで、xmとアノテーションlに基づいてSpringフレームワークの構成を確認します。何か問題がある場合は、以下にメッセージを残してください。フレームワークの理解を深め、皆様のお役に立てれば幸いです。ありがとうございます。
春のフレームワークの2つのコアアイデア
制御のIOC反転
IOCは(Inversion of Control)の略で、制御の反転です。私自身の理解(笑)を使用することは、SpringのIOCコンテナーにオブジェクトを作成する権利を与え、IOCコンテナーにオブジェクトのインスタンス化を実装させることです。これは、プログラム間の結合を減らす効果があります。IOCに関しては、依存関係の注入という概念があります。これについては後で説明します。
AOPアスペクト指向プログラミング
AOP、すなわち(アスペクト指向プログラミング)、アスペクト指向プログラミング。シナリオがあるとします。小さなプロジェクトを自分で作成すると、現時点では、データベースを操作するための数十のメソッドにトランザクション制御がないことがわかります。これで問題ありません。各メソッドを1つずつ試してみる必要があります。キャッチ/最後に、あなたは不快になります。AOPのアイデアはこの結合をうまく解決します。
XMLベースのIOC構成プロセス(IDEA)
最初にmavenプロジェクトを作成し、次にpom.xmlファイルで依存関係を構成します
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
</dependencies>
座標の導入が遅い場合は、Alibaba Cloudのイメージに変更でき、方法はBaiduにすることができ、多くのチュートリアルがあることを確認してください。
次に、新しいエンティティクラスを作成します
/**用户信息实体类
* @author Cocowwy
* @create 2020-04-04-23:56
*/
public class User {
private String name;
private Integer 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;
}
}
}
次に、main / resourcesディレクトリの下に構成ファイルを書き込みます。最初にこのブロックを書き込みます。
<?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">
</beans>
エンティティクラスを作成したばかりなので、IOCを使用してインスタンスを作成し、構成します。
<bean id="user" class="cn.hncu.domain.User"></bean>
IDは自分で名前を付けますが、コードでインスタンスオブジェクトを作成する場合は、このIDを一意の識別子として必要です。class属性は、クラスの完全修飾クラス名です。
クラスと構成ファイルを使用して、コード内の構成ファイルを読み取ることにより、インスタンスオブジェクトをどのように取得しますか??
JAVAコードの場合:
/**
* @author Cocowwy
* @create 2020-04-04-0:09
*/
public class test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//返回结果是obj类型,记得强转!
System.out.println(ac.getBean("user"));//控制台输出:cn.hncu.domain.User@3ffc5af1
}
}
アドレスを印刷して、オブジェクトが正常に作成されたことを示します。これは制御の反転であり、新しいオブジェクトの制御力をスプリングコンテナに転送します。
では、どのようにオブジェクトに値を割り当てますか?
方法1:工法による
<bean id="user" class="cn.hncu.domain.User">
<constructor-arg index="0" value="王小胖"/>
<constructor-arg index="1" value="20"/>
</bean>
エンティティクラスにコンストラクタメソッドを追加すると(alt + insはコンストラクタを生成します)、アイデアにより、構成ファイルに新しいラベルconstructor-argが必要であることが示されます。ラベルインデックスはパラメータの数を示します。添え字は0から始まることに注意してください。値は、割り当てる必要のある値です。
次に、エンティティクラスのtosSring()メソッドを書き直して、結果を確認します。
//构造函数
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
//重写toString
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
テスト:
/**
* @author Cocowwy
* @create 2020-04-04-0:09
*/
public class test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//返回结果是obj类型,记得强转!
System.out.println(ac.getBean("user"));//控制台输出:User{name='王小胖', age=20}
}
}
割り当てが成功したことがわかります。
方法2:属性インジェクションを介して(より一般的に使用されます)
最初に前のメソッドのコンストラクターを削除し、
次のように構成します
<bean id="user" class="cn.hncu.domain.User">
<property name="name" value="王大胖"></property>
<property name="age" value="21"></property>
</bean>
プロパティタグのname属性は、エンティティクラスの属性名を参照し、値は割り当てられた値です。
テスト:
/**
* @author Cocowwy
* @create 2020-04-04-0:09
*/
public class test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//返回结果是obj类型,记得强转!
System.out.println(ac.getBean("user"));//控制台输出:User{name='王大胖', age=21}
}
}
基本的なツリープロパティの挿入がわかったので、コレクション、マップ、配列などの特別なプロパティについて説明しましょう。プロパティに値を割り当てるにはどうすればよいですか?
最初はリストコレクションです
最初にエンティティクラスを変更し、getsetメソッドを介して挿入します
/**
* 用户信息实体类
*
* @author Cocowwy
* @create 2020-04-04-23:56
*/
public class User {
private String name;
private Integer age;
private List<String> frinds;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", frinds=" + frinds +
'}';
}
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;
}
public List<String> getFrinds() {
return frinds;
}
public void setFrinds(List<String> frinds) {
this.frinds = frinds;
}
}
その場合、bean.xmlの構成は次のようになります。
<bean id="user" class="cn.hncu.domain.User">
<property name="name" value="王小胖"></property>
<property name="age" value="20"></property>
<property name="frinds" >
<array>
<value>王一胖</value>
<value>王二胖</value>
<value>王三胖</value>
</array>
</property>
</bean>
プロパティタグのname値がリストの名前であり、プロパティにarryタグが含まれていることがわかります。各値は、セット内の各値に対応しています。
結果は次のとおりです。
/**
* @author Cocowwy
* @create 2020-04-04-0:09
*/
public class test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//返回结果是obj类型,记得强转!
System.out.println(ac.getBean("user"));//User{name='王小胖', age=20, frinds=[王一胖, 王二胖, 王三胖]}
}
}
配列とリストの手順は同じであるため、ここでは説明しません。
次はマップコレクションです
属性とgeisetメソッドをエンティティに追加し、toStringを書き換えます
package cn.hncu.domain;
import java.util.List;
import java.util.Map;
/**
* 用户信息实体类
*
* @author Cocowwy
* @create 2020-04-04-23:56
*/
public class User {
private String name;
private Integer age;
private List<String> frinds;
private Map<String,String> thingColor;
public Map<String, String> getThingColor() {
return thingColor;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", frinds=" + frinds +
", thingColor=" + thingColor +
'}';
}
public void setThingColor(Map<String, String> thingColor) {
this.thingColor = thingColor;
}
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;
}
public List<String> getFrinds() {
return frinds;
}
public void setFrinds(List<String> frinds) {
this.frinds = frinds;
}
}
その場合、bean.xmlの構成は次のようになります
<bean id="user" class="cn.hncu.domain.User">
<property name="name" value="王小胖"></property>
<property name="age" value="20"></property>
<property name="frinds" >
<array>
<value>王一胖</value>
<value>王二胖</value>
<value>王三胖</value>
</array>
</property>
<property name="thingColor">
<map>
<entry key="上衣" value="红色"></entry>
<entry key="裤子" value="蓝色"></entry>
<entry key="头发" value="黑色"></entry>
</map>
</property>
</bean>
マップコレクションという名前のプロパティタグがマップタグをラップしていることがわかります。マップには、わかりやすいキーと値のペアを表すエントリタグがあります。
テスト:
package cn.hncu;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Cocowwy
* @create 2020-04-04-0:09
*/
public class test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//返回结果是obj类型,记得强转!
System.out.println(ac.getBean("user"));//User{name='王小胖', age=20, frinds=[王一胖, 王二胖, 王三胖], thingColor={上衣=红色, 裤子=蓝色, 头发=黑色}}
}
}
プロパティ?
同じgetsetメソッドを追加してtoStringを書き換えます
private Properties properties;
bean.xmlの新しい構成
<property name="properties">
<props>
<prop key="体重">140</prop>
</props>
</property>
テスト:
package cn.hncu;
import cn.hncu.domain.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* @author Cocowwy
* @create 2020-04-04-0:09
*/
public class test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//返回结果是obj类型,记得强转!
System.out.println(ac.getBean("user"));
// User {name='王小胖', age=20, frinds=[王一胖, 王二胖, 王三胖], thingColor={上衣=红色, 裤子=蓝色, 头发=黑色}, properties={体重=140}}
}
}
コレクションに必要な他の参照タイプはどうですか???
最初に2つのエンティティを作成すると、リストコレクションの一般的なタイプがアカウントであることがわかります。
package cn.hncu.domain;
import java.util.List;
import java.util.Map;
import java.util.Properties;
/**
* 用户信息实体类
*
* @author Cocowwy
* @create 2020-04-04-23:56
*/
public class User {
private String name;
private Integer age;
private List<Account> accounts;
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
", accounts=" + accounts +
'}';
}
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;
}
public List<Account> getAccounts() {
return accounts;
}
public void setAccounts(List<Account> accounts) {
this.accounts = accounts;
}
}
アカウントエンティティ
package cn.hncu.domain;
/**
* @author Cocowwy
* @create 2020-04-04-11:32
*/
public class Account {
private String username;
private String money;
@Override
public String toString() {
return "Account{" +
"username='" + username + '\'' +
", money='" + money + '\'' +
'}';
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getMoney() {
return money;
}
public void setMoney(String money) {
this.money = money;
}
}
次に構成する方法は?これは、この場所が適切なマップであろうと配列であろうと、そのためにエンティティを導入する必要がある場所を明確に理解しています。
bean.xmlの構成は次のとおりです。
<bean id="account" class="cn.hncu.domain.Account">
<property name="username" value="王小胖工行卡"></property>
<property name="money" value="300000"></property>
</bean>
<bean id="user" class="cn.hncu.domain.User">
<property name="name" value="王小胖"></property>
<property name="age" value="20"></property>
<property name="accounts">
<list>
<ref bean="account"></ref>
</list>
</property>
</bean>
まず、新しいエンティティを作成したので、当然、それをIOCコンテナに挿入する必要があります。最初に構成すると、Beanのプロパティにref属性があることがわかりますか?これで、refによって参照されるBeanは、IOCコンテナに挿入したばかりのid = accountのBeanであり、refはidによって検出されます。類推すると、value属性をref属性に置き換えることで、IOCコンテナ内のBeanを参照していると結論付けるのは難しくありません。
テスト:
/**
* @author Cocowwy
* @create 2020-04-04-0:09
*/
public class test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//返回结果是obj类型,记得强转!
System.out.println(ac.getBean("user"));
//User{name='王小胖', age=20, accounts=[Account{username='王小胖工行卡', money='300000'}]}
}
}
上記は、エンティティに値を割り当てる方法、つまりDIの依存関係の注入です。これはSpringのXMLベースのIOC構成です。比較的大まかな構成ですが、比較的単純な構成です。
XMLベースのAOP構成プロセス(IDEA)
SpringでのXMLベースのAOP構成
1.管理する
Springに通知Beanを提供します2.aop:configタグを
使用してAOP構成の開始を示します3. aop:aspectタグを使用してアスペクト
ID属性の構成の開始を示します:アスペクトに一意のフラグ
参照を提供します属性:通知クラスを指定するBeanのID
4. aop:aspectタグ内の対応するタグを使用して、通知のタイプを構成します。
現在の例では、pointcutメソッドが実行される前にpringLogメソッドが実行されるため、
aop:beforeに事前通知します。 :事前通知
メソッド属性の構成を示します:Loggerクラスのどのメソッドを指定するために使用されますか、事前通知
ポイントカット属性:エントリポイント式を指定するために使用されます。式の意味は、ビジネスレイヤーのどのメソッドが
エントリポイント式を拡張するかを示します。タイプの書き込み:
キーワード:実行(式)
式:
アクセス修飾子の戻り値パッケージ名。パッケージ名。パッケージ名...クラス名。メソッド名(パラメーターリスト)
標準の書き込み:public void com.hncu.service.impl .AccountServiceAOP.saveAccount()
アクセス修飾子は省略できます:void com.hncu.service.impl.AccountServiceAOP.saveAccount()
戻り値はワイルドカードを使用できます:任意の戻り値を示します:* com.hncu.service.impl.AccountServiceAOP.saveAccount( )
包名可以使用通配符表示任意包,表示任意包,但是有几级包,就需要写几个*.:* ...…AccountServiceAOP.saveAccount()
包名还可以使用…表示当前包及其子包:* …AccountServiceAOP.saveAccount()
类名和方法名都可以使用来实现通配:* ….()
参数列表:
可以直接写数据类型
基本类型直接写名称 int
引用类型写包名.类名的方式 java.lang.String
可以使用通配符表示任意类型,但必须有参数
可以使用…表示有无参数均可,有参数可以使任意类型
全统配写法: ….(…)
实际开发中切入点表达式的通常写法
切刀业务层实现类下的所有方法
* com.hncu.service.impl..*(…)
依赖:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>commons-dbutils</groupId>
<artifactId>commons-dbutils</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
<dependency>
<groupId>c3p0</groupId>
<artifactId>c3p0</artifactId>
<version>0.9.1.2</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.7</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.0.2.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.6</version>
</dependency>
</dependencies>
AOP切面的配置
!-- 配置AOP-->
<aop:config>
<!--配置切入点表达式 id:用于指定表达式的唯一表示 expression:用于指定表达式内容
此标签卸写在aop:aspect标签内部只能当前切面使用。
它还可以写在aop:aspect外面(标签必须在切面你之前!!!!!!)-->
<aop:pointcut id="pt1" expression="execution(* com.hncu.service.impl.*.*(..))"/>
<!--配置切面-->
<aop:aspect id="logAdvice" ref="logger">
<!-- 配置通知的类型,并且建立通知方法和切入点方法的关联-->
<!-- 前置通知,在切入点执行方法之前执行-->
<aop:before method="beforeprintLog" pointcut-ref="pt1"></aop:before>
<!-- 后置通知,在切入点方法正常执行之后执行,它和异常通知永远只能执行一个-->
<aop:after-returning method="afterReturnprintLog" pointcut-ref="pt1"></aop:after-returning>
<!-- 异常通知,在切入点方法执行异常之后执行,它和后置通知永远只能执行一个-->
<aop:after-throwing method="afterThrowingprintLog" pointcut-ref="pt1"></aop:after-throwing>
<!-- 最终通知,无论切入点方法是否正常执行它都会在其后面执行-->
<aop:after method="afterprintLog" pointcut-ref="pt1"></aop:after>
<!-- 配置环绕通知 详细的注释请看Logger类中-->
<aop:around method="arroundPrintLog" pointcut-ref="pt1"></aop:around>
</aop:aspect>
</aop:config>
Logger类。
package com.hncu.utils;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* @author Cocowwy
* @create 2020-04-04-11:23
* 用于记录日志的工具类,它里面提供了公共代码
*/
public class Logger {
/**
* 用于打印日志,计划让其在切入点方法执行之前执行(切入点方法就是业务层方法)
* 前置通知
*/
public void beforeprintLog() {
System.out.println("前置通知Logger类中的beforeprintLog方法开始记录日志了。。。");
}
/**
* 后置通知
*/
public void afterReturnprintLog() {
System.out.println("后置通知Logger类中的afterReturnprintLog方法开始记录日志了。。。");
}
/**
* 异常通知
*/
public void afterThrowingprintLog() {
System.out.println("异常通知Logger类中afterThrowingprintLog方法开始记录日志了。。。");
}
/**
* 最终通知
*/
public void afterprintLog() {
System.out.println("最终通知Logger类中的afterprintLog方法开始记录日志了。。。");
}
/**
* 环绕通知
* 问题:当我们配置了环绕通知之后,切入点方法没有执行,通知方法执行了
* 分析:通过对比动态代理中的环绕通知代码,发现动态代理中环绕通知有明确的切入点方法调用
* 而我们的代码中没有,
* 解决:spring框架为我们提供了一个接口:ProceedingJoinPoint该接口有一个方法proceed(),
* 此方法就相当于明确调用切入点方法
* 该接口可以作为环绕通知的方法参数,在程序执行时spring框架会为我们提供该接口的实现类供我们使用
* <p>
* spring中的环绕通知:
* 它是spring框架为我们提供的一种可以在代码中手动控制增强方式何时执行的方式
*/
public Object arroundPrintLog(ProceedingJoinPoint pjp) {
Object rtvalue = null;
try {
Object[] args = pjp.getArgs();//得到方法执行所需的参数
System.out.println("环绕前置通知");
rtvalue = pjp.proceed(args);//明确调用业务层方法(切入点方法)
System.out.println("环绕后置通知");
return rtvalue;
} catch (Throwable throwable) {
System.out.println("环绕异常通知");
throw new RuntimeException(throwable);
} finally {
System.out.println("环绕最终通知");
}
}
}
以上就是基于XML的配置,稍后会进行spring基于注解的配置!