1. 程式人生 > 實用技巧 >QT-Qt設定背景圖片

QT-Qt設定背景圖片

1 簡介

1.1 歷史

  • Spring框架以interface21框架為基礎,經過重新設計,並不斷豐富其內涵,與2004年3月24日釋出了1.0正式版

  • 作者為Rod Johnson

1.2 理念

  • 使現有的技術更加容易使用
  • 本身包括很多內容,並整合了現有的技術框架

1.3 優點

  • Spring是一個開源的免費的框架(容器)
  • Spring是一個輕量級的、非入侵式的框架
  • 控制反轉(IOC)
  • 面向切面程式設計(AOP)
  • 支援事務的處理

1.4 組成

1.5 其他

  • Spring Boot
    • 一個快速開發的框架
    • 基於Spring Boot可以快速開發單個微服務
  • Spring Cloud
    • 基於Spring Boot實現

2 IoC

以前的JavaWeb專案開發流程,比如

  1. 寫UserDao介面
public interface UserDao {
    //方法
}
  1. 寫UserDaoImpl實現類
public class UserDaoImpl implements UserDao {
    //方法實現
}
  1. 寫UserService業務介面
public interface UserService {
    //方法
}
  1. 寫UserServiceImpl業務實現類
public class UserServiceImpl implements UserService {
    private UserDao userDao = new UserDaoImpl();
    
    //方法實現
}
  1. 測試
@Test
public void test() {
    UserService userService = new UserServiceImpl();
    //呼叫userService的方法
}

這種方法的弊端在於使用者的需求可能會影響程式碼,需要根據使用者需求去修改程式碼,代價很大

那麼,如果在UserServiceImpl中使用set介面,程式變為

public class UserServiceImpl implements UserService {
    private UserDao userDao;
    //利用set進行動態注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    
    //方法實現
}

測試的時候程式碼變為

@Test
public void test() {
    UserService userService = new UserServiceImpl();
    (UserServiceImpl) userService.setUserDao(new UserDaoImpl());
    //呼叫userService的方法
}

使用set注入後,程式不再具有主動性,變成了被動的接收物件。主動權轉到了使用者,使用者選擇實現類物件

這種思想從本質上解決了問題,程式設計師不用管理物件的建立,降低了系統的耦合,從而專注業務的實現,這就是IoC的原型

2.1 IoC本質

控制反轉(IoC, Inversion of Control)是一種設計思想。在沒有IoC的程式中,使用面向物件程式設計,物件的建立和物件間的依賴關係完全硬編碼在程式中,物件的建立由程式自己控制。而控制反轉則是將物件的建立轉移給第三方

控制反轉是一種通過描述(XML或註解)並通過第三方去生產或獲取特定物件的方式,在Spring中實現控制反轉的是IoC容器,其實現方法是依賴注入(DI, Dependency Injection)

3 HelloSpring

  1. 編寫實體類
public class Hello {
    private String str;
    
    public void setStr(String str) {
        this.str = str;
    }
    
    public String getStr() {
        return str;
    }
}
  1. 配置xml檔案
<bean id="hello" class="com.hjc.pojo.Hello">
    <property name="str" value="Hello, world"/>
</bean>
  1. 測試
@Test
public void test() {
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Hello hello = (Hello) context.getBean("hello");
    System.out.println(hello);
}

要實現不同的操作,我們只需要在xml檔案中修改。物件由Spring來建立,管理,裝配

4 IoC建立物件的方式

4.1 無參建構函式建立物件

要用無參建構函式建立物件,那麼類中就要保留無參建構函式,要麼顯示寫出無參建構函式,要麼就不寫建構函式

public class User {
    private int id;
    private String name;
    
    public void setId(int id) {
        this.id = id;
    }
    
    public void setName(String name) {
        this.name = name;
    }
    
    //其他函式
}

此時,在配置xml時就如上文那樣,資料注入是由set注入的,那麼在類中就要寫出屬性的set方法

<bean id="user" class="com.hjc.pojo.User">
    <property name="id" value="1"/>
    <property name="name" value="admin"/>
</bean>

用這種方式配置,那麼物件是先由類的無參建構函式建立,再由類的set方法進行資料的注入,要注意這個先後順序

4.2 有參建構函式建立物件

如果要使用有參建構函式建立物件,那麼在類中就要寫出有參建構函式。此時,資料是由有參建構函式注入

public class User {
    private int id;
    private String name;
    
    public User(int id, String name) {
        this.id = id;
        this.name = name;
    }
}

在配置xml檔案時就和上文不太一樣

<bean id="user" class="com.hjc.pojo.User">
    <constructor-arg index="0" value="1"/>
    <constructor-arg index="1" value="admin"/>
</bean>
<bean id="user" class="com.hjc.pojo.User">
    <constructor-arg type="int" value="1"/>
    <constructor-arg type="java.lang.String" value="admin"/>
</bean>
<bean id="User" class="com.hjc.pojo.User">
    <constructor-arg name="id" value="1"/>
    <constructor-arg name="name" value="admin"/>
</bean>

以上三種方法都可以實現相同的效果。以這種方式配置,物件就由類的有參建構函式建立,而資料也是由有參建構函式注入

不管物件是由無參建構函式還是有參建構函式建立的,在配置檔案載入的時候,容器中的物件就已經被初始化了

5 Spring配置

5.1 別名

Spring中別名的使用和MyBatis中類似,使用別名之後可以省略類的包路徑

5.2 bean的配置

<!--
id: bean的唯一識別符號
class: bean物件對應的全限定名
name: 別名,可以取多個別名
scope: bean為單例還是多例
-->
<bean id="user" class="com.hjc.pojo.User" name="user2" scope="singleton">
    <property name="id" value="1"/>
    <property name="name" value="admin"/>
</bean>

5.3 使用import

將多個配置檔案匯入合併為一個配置檔案。比如,在applicationContext.xml檔案中匯入service.xml和dao.xml配置檔案,將這兩個配置檔案合併為一個applicationContext.xml配置檔案

<import resource="service.xml"/>
<import resource="dao.xml"/>

6 依賴注入

6.1 構造器注入

參考4.2

6.2 set方式注入

  • 依賴注入
    • 依賴:bean物件的建立依賴於容器
    • 注入:bean物件的所有屬性由容器注入

例項

  1. 編寫實體類
public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbies;
    private Map<String, String> scores;
    private Set<String> games;
    private String nullPoint;
    private Properties info;
    
    //一定要寫各屬性的set方法,在此省略
}
public class Address {
    private String address;
    
    public setAddress(String address) {
        this.address = address;
    }
}
  1. 配置xml檔案,使用set方法注入
<bean id="address" class="com.hjc.pojo.Address">
    <property name="address" value="testAddress"/>
</bean>

<bean id="student" class="com.hjc.pojo.Student">
    <!--基本型別(包括String)注入,value-->
    <property name="name" value="test"/>
    <!--bean注入,ref-->
    <property name="address" ref="address"/>
    <!--陣列注入,-->
    <property name="books">
        <array>
            <value>testBook1</value>
            <value>testBook2</value>
            <value>testBook3</value>
        </array>
    </property>
    <!--list注入-->
    <property name="hobbies">
        <list>
            <value>testHobby1</value>
            <value>testHobby2</value>
        </list>
    </property>
    <!--map注入-->
    <property name="scores">
        <map>
            <entry key="Math" value="100"/>
            <entry key="Physics" value="100"/>
        </map>
    </property>
    <!--set注入-->
    <property name="games">
        <set>
            <value>testGame1</value>
            <value>testGame2</value>
        </set>
    </property>
    <!--null注入-->
    <property name="nullPoint">
        <null/>
    </property>
    <!--properties注入-->
    <property name="info">
        <props>
            <prop key="testInfo1">test1</prop>
            <prop key="testInfo2">test2</prop>
        </props>
    </property>
</bean>
  1. 測試
@Test
public void test() {
    ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
    Student student = (Student) context.getBean("student");
    System.out.println(student);
}

6.3 其他方式注入

p名稱空間,對應set注入,參考官方文件

c名稱空間,物件構造器注入,參考官方文件

7 bean的作用域

7.1 singleton

單例模式,也是Spring的預設模式,不顯示寫出就表示單例

單例模式表示在容器中物件只會建立一個

7.2 prototype

原型模式,表示每次從容器中獲得物件的時候,容器會建立一個新的物件返回

7.3 request、session、application

這幾個在web開發中使用

8 bean的自動裝配

之前的xml配置都是手動配置的,那麼自動裝配是Spring會在上下文中自動尋找,自動裝配屬性

在Spring中有三種裝配的方式

  • 在xml中顯示配置
  • 在java類中顯示配置
  • 隱式自動裝配

8.1 byName自動裝配

public class Student {
    private String name;
    private Computer computer;
    private KeyBoard keyBoard;
    
    //set方法
}
public class Computer {
}

public class KeyBoard {
}

有三個實體類,用byName自動裝配配置xml

<bean id="computer" class="com.hjc.pojo.Computer"/>
<bean id="keyBoard" class="com.hjc.pojo.KeyBoard"/>
<!--
byName: 自動在容器上下文中查詢和自己物件set方法後面的值對應的bean id
如:類中setComputer方法,Computer對應bean id為computer
-->
<bean id="student" class="com.hjc.pojo.Student" autowire="byName">
    <property name="name" value="test"/>
</bean>

這種方法要求bean的id不能隨便選擇,要和自動注入的屬性的set方法的值一致,除了首字母大寫變成小寫

8.2 byType自動裝配

還是上面三個實體類,用byType實現自動裝配

<bean id="computer" class="com.hjc.pojo.Computer"/>
<bean id="keyBoard" class="com.hjc.pojo.KeyBoard"/>
<!--
byType: 會自動在容器上下文中查詢和自己物件屬性型別相同的bean
-->
<bean id="student" class="com.hjc.pojo.Student" autowire="byType">
    <property name="name" value="test"/>
</bean>

這種方法要求物件中屬性型別要唯一,如果有幾個相同的屬性型別,就不能自動裝配

8.3 註解自動裝配

jdk1.5支援註解,spring2.5支援註解

要使用註解

  1. 匯入約束,context約束
  2. 配置註解的支援
<context:annotation-config/>

使用@Autowired註解,直接在屬性上使用,或者在set方法上使用。另外,使用@Autowired註解可以不寫set方法,前提是屬性符合byType的要求

實體類

public class Student {
    private String name;
    @Autowired
    private Computer computer;
    @Autowired
    private KeyBoard keyBoard;
    
    //set方法
}

xml檔案

<bean id="computer" class="com.hjc.pojo.Computer"/>
<bean id="keyBoard" class="com.hjc.pojo.KeyBoard"/>
<bean id="student" class="com.hjc.pojo.Student"/>

如果使用@Autowired實現自動裝配的環境比較複雜,無法通過一個註解完成的時候,可以配合使用@Qualifier(value="xxx")來指定唯一的一個bean

9 使用註解開發

在Spring4之後,要使用註解開發,必須要匯入aop的包。另外,需要在xml檔案中匯入context約束,配置註解的支援

<context:annotation-config/>

首先,要配置掃描的包,也就是說,在類中配置了註解還要被掃描到才有效

<context:component-scan base-package="com.hjc"/>

9.1 @Component

這個註解放在類上,表示這個類被Spring管理了,比如

@Component
public class User {
    //省略
}

相當於在xml檔案中配置bean

<bean id="user" class="com.hjc.pojo.User"/>

9.2 @Value

這個註解放在類中的屬性上,表示注入資料,比如

@Component
public class User {
    @Value("test")
    private String name;
}

相當於在xml檔案中配置bean,並進行依賴注入

<bean id="user" class="com.hjc.pojo.User">
    <property name="name" value="test"/>
</bean>

@Value註解也可以放在屬性的對應set方法上,但這個註解只能進行簡單的配置,複雜的配置還是使用xml檔案

9.3 @Component的衍生註解

web專案一般有三層,不同層中的註解名稱不同,但作用相同

  • Dao層:@Repository
  • Service層:@Service
  • Controller層:@Controller

這幾個註解和@Component是一樣的,都表示將類註冊到Spring中,裝配bean

9.4 @Autowired

這個註解實現自動裝配,參考8.3

9.5 @Scope

這個註解配置類的作用域,是單例模式還是原型模式,比如

@Component
@Scope("singleton")
public class User {
    @Value("test")
    private String name;
}

總結:

  • xml檔案配置更加萬能,適用於任何場合,維護簡單
  • 註解適用於簡單的配置,維護相對複雜
  • 專案中一般使用xml管理bean,使用註解完成屬性注入

10 使用JavaConfig配置

不使用xml檔案配置,都由Java程式碼配置

JavaConfig是Spring的一個子專案,在Spring4之後,稱為一個核心功能

10.1 @Configuration、@Bean

要用Java程式碼進行配置,就要用到@Configuration和@Bean這兩個註解,比如

@Configuration
public class AppConfig {
    @Bean
    public User getUser() {
        return new User();
    }
}

這就相當於在xml中配置

<bean id="getUser" class="com.hjc.pojo.User"/>

測試

@Test
public void test() {
    ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
    User user = context.getBean("getUser");
}

注意和xml檔案配置例項化物件的不同

10.2 @ComponentScan

在配置類中使用這個註解表示設定掃描類包

@Configuration
@ComponentScan("com.hjc")
public class AppConfig {
    @Bean
    public User getUser() {
        return new User();
    }
}

11 代理模式

代理模式是SpringAOP的底層實現

代理模式有兩種

  • 靜態代理
  • 動態代理

11.1 靜態代理

角色分析

  • 抽象角色:一般會使用介面或者抽象類來解決
  • 真實角色:被代理角色
  • 代理角色:代理真實角色,代理真實角色後,一般會做附加操作
  • 客戶:訪問代理物件的人

使用靜態代理的例子

  1. 編寫介面(抽象角色)
//租房介面
public interface Rent {
    void rent();
}
  1. 編寫被代理類(真實角色)
//房東
public class Host implements Rent {
    @Override
    public void rent() {
        System.out.println("房東出租房子");
    }
}
  1. 編寫代理類(代理角色)
public class Proxy implements Rent {
    private Host host;
    
    public Proxy() {
    }
    
    public Proxy(Host host) {
        this.host = host;
    }
    
    @Override
    public void rent() {
        findHouse();
        host.rent();
        signContract();
    }
    
    public void findHouse() {
        System.out.println("找到房子");
    }
    
    public void signContract() {
        System.out.println("籤合同");
    }
}
  1. 編寫客戶訪問代理角色
public class Client {
    public static void main(String[] args) {
        Proxy proxy = new Proxy(new Host());
        proxy.rent();
    }
}

靜態代理的好處:

  • 可以使真實角色的操作更加純粹,不用關注一些公共的業務
  • 公共業務交給代理角色,實現了業務的分工
  • 公共業務發生擴充套件的時候,方便集中管理

缺點:

  • 一個真實角色就會產生一個代理角色,增加程式碼量,開發效率低

在web開發中,如果要對類中的方法進行增強,直接改類中對應方法的程式碼比較繁瑣,而且實際開發不允許直接改程式碼,我們可以使用靜態代理實現,舉個例子加深理解

  1. 編寫service介面
public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}
  1. 編寫service實現類
public class UserServiceImpl implements UserService {
    //實現對應方法
}
  1. 編寫代理類
public class UserServiceProxy implements UserService {
    private UserService userService;
    
    public void setUserService(UserService userService) {
        this.userService = userService;
    }
    
    public void add() {
        log("add");
        userService.add();
    }
    
    public void delete() {
        log("delete");
        userService.delete();
    }
    
    public void update() {
        log("update");
        userService.update();
    }
    public void query() {
        log("query");
        userService.find();
    }
    
    public void log(String msg) {
        System.out.println("[debug] 使用了" + msg + "方法");
    }
}
  1. 客戶訪問
public class Client {
    public static void main(String[] args) {
        UserServiceProxy proxy = new UserServiceProxy();
        proxy.setUserService(new UserServiceImpl);
        proxy.add();
        proxy.delete();
        proxy.update();
        proxy.query();
    }
}

這樣子就避免修改了原有的service程式碼,而是通過代理類對service類的方法進行增強

11.2 動態代理

  • 動態代理和靜態代理的角色一樣
  • 動態代理的代理類是動態生成的,不是直接寫好的
  • 動態代理分為兩大類
    • 基於介面的動態代理:jdk動態代理
    • 基於類的動態代理:cglib
    • 還有基於java位元組碼實現:Javassist

需要了解兩個類:Proxy,InvocationHandler

動態代理的好處

  • 動態代理有靜態代理的優點
  • 另外,一個動態代理類代理的是一個介面,一般對應一類業務,解決了靜態代理的缺點

12 AOP

12.1AOP定義

AOP(Aspect Oriented Programming),面向切面程式設計,通過預編譯方式和執行期動態代理實現程式功能統一維護的技術。AOP是OOP的延續,是函數語言程式設計的一種衍生範型

12.2 AOP在Spring中的作用

提供宣告式事務,允許使用者自定義切面

  • 橫切關注點:跨越應用程式多個模組的方法或功能,如日誌,安全,快取,事務等等
  • 切面(Aspect):橫切關注點被模組化的特殊物件,即是一個類
  • 通知(Advice):切面必須要完成的工作,即是類中的一個方法
  • 目標(Target):被通知物件
  • 代理(Proxy):向目標物件應用通知之後建立的物件
  • 切入點(PointCut):切面通知執行的“地點”
  • 連線點(JointPoint):與切入點匹配的執行點

SpringAOP中,通過Advice定義橫切邏輯,Spring支援5種類型的Advice

  • 前置通知
    • 連線點:方法前
    • 實現介面:org.springframework.aop.MethodBeforeAdvice
  • 後置通知
    • 連線點:方法後
    • 實現介面:org.springframework.aop.AfterReturningAdvice
  • 環繞通知
    • 連線點:方法前後
    • 實現介面:org.aopalliance.intercept.MethodInterceptor
  • 異常丟擲通知
    • 連線點:方法丟擲異常
    • 實現介面:org.springframework.aop.ThrowsAdvice
  • 引介通知
    • 連線點:類中增加新的方法屬性
    • 實現介面:org.springframework.aop.IntroductionInterceptor

AOP在不改變原有程式碼的情況下, 增加新的功能

11.3 使用Spring實現AOP

要使用AOP織入,需要匯入包

<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.5</version>
</dependency>

假設有service介面和實現類

public interface UserService {
    void add();
    void delete();
    void update();
    void query();
}
public class UserServiceImpl implements UserService {
    //實現對應方法
}

那麼,要對這幾個方法使用AOP進行方法增強

方式一:使用Spring的API實現

  1. 首先要定義切面和通知,定義類實現對應介面
public class BeforeLog implements MethodBeforeAdvice {
    //Method: 被代理的目標物件的方法
    //args: 方法引數
    //target: 被代理的目標物件
    @Override
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println("執行" + target.getClass().getName() + "的" + method.getName());
    }
}
public class AfterLog implements AfterReturningAdvice {
    //returnValue: 被代理的方法的返回值
    @Override
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        System.out.println("執行" + method.getName() + "返回結果" + returnValue);
    }
}
  1. 在xml中配置,把這些類註冊到Spring中
<!--註冊bean-->
<bean id="userService" class="com.hjc.service.UserServiceImpl"/>
<bean id="beforeLog" class="com.hjc.log.BeforeLog"/>
<bean id="afterLog" class="com.hjc.log.AfterLog"/>

<!--配置aop,匯入aop約束-->
<aop:config>
    <!--切入點,expression表示式-->
    <aop:pointcut id="pointcut" expression="execution(* com.hjc.service.UserServiceImpl.*(..))"/>
    <!--執行增強-->
    <aop:advisor advice-ref="beforeLog" pointcut-ref="pointcut"/>
    <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
  1. 測試
@Test
public void test() {
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    //動態代理的是介面
    UserService userService = (UserService) context.getBean("userService");
    userService.add();
    userService.delete();
}

方式二:自定義實現AOP

不通過實現Spring的介面來實現AOP,而是自己定義切面類和通知

public class MyLog {
    public void beforeLog() {
        //具體實現
    }
    
    public void AfterLog() {
        //具體實現
    }
}

同樣,在xml中配置

<bean id="myLog" class="com.hjc.log.MyLog"/>

<aop:config>
    <!--自定義切面-->
    <aop:aspect ref="myLog">
        <!--切入點-->
        <aop:pointcut id="pointcut" expression="execution(* com.hjc.service.UserServiceImpl.*(..))"/>
        <!--通知-->
        <aop:before method="beforeLog" pointcut-ref="pointcut"/>
        <aop:after method="afterLog" pointcut-ref="pointcut"/>
    </aop:aspect>
</aop:config>

方式三:註解實現AOP

使用註解實現AOP,主要是在定義切面類的時候使用註解

@Aspect
public class MyLog {
    @Before("execution(* com.hjc.service.UserServiceImpl.*(..))")
    public void before() {
        //具體實現
    }
    
    @After("execution(* com.hjc.service.UserServiceImpl.*(..))")
    public void after() {
        //具體實現
    }
}

在xml中只需註冊bean,當然也可以使用註解自動裝配。還要開啟註解支援

<bean id="myLog" class="com.hjc.log.MyLog"/>
<aop:aspectj-autoproxy/>

13 整合MyBatis

步驟

  1. 匯入相關jar包
    • junit
    • mybatis
    • mysql
    • spring
    • aop織入
    • mybatis-spring
  2. 編寫配置檔案

13.1 MyBatis

13.2 MyBatis-Spring

參考官方文件

  1. 編寫資料來源配置
  2. sqlSessionFactory
  3. sqlSessionTemplate
  4. 給Dao介面編寫實現類
  5. 註冊實現類到Spring中
  6. 測試

14 宣告式事務

14.1 事務

  • 事務涉及資料的完整性和一致性問題
  • 事務ACID原則
    • 原子性
    • 一致性
    • 隔離性
    • 永續性

14.2 Spring中的事務管理

  • 宣告式事務:AOP
  • 程式設計式事務:在程式碼中進行事務管理

一般使用宣告式事務,而不是用程式設計式事務,因為程式設計式事務會改變程式碼

  1. 在xml中配置宣告式事務
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" value="dataSource"/>
</bean>
  1. 結合AOP實現事務織入
<!--配置事務通知-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <!--給具體方法配置事務-->
    <tx:attributes>
        <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.hjc.mapper.*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="txPointCut"/>
</aop:config>