こんにちは
Spring MVCは、2014 RevbelLabs Java Tools and Technology Reviewによると、最も人気のあるWebフレームワークです。
さらに、同じレビューではORMのリーダーであるHibernateとWebコンテナーのリーダーであるApache Tomcatを呼び出しています。 ここに、 jQueryライブラリ、最も使用されているJavaスクリプト、最も人気のあるBootstrap cssフレームワーク、最も人気のあるMavenビルドツール(Gradle攻撃に関係なく)、 JUnitテストフレームワークの絶対的なリーダーを追加します。
Spring Pet Clinic ( デモアプリケーション )。
上記に加えて、Spring-Jdbc、Spring-ORMも機能プロジェクトの観点から、このかなりシンプルに含まれています。
Spring Data JPA 、
Hibernateバリデーター 、
SLF4J 、
ジョンソン・ジャクソン
JSP
JSTL 、
WebJars
タンポポDataTables 、
HSQLDB 、
ハムクレスト 、
Mockitoおよびその他多数の依存関係。
ソフトウェア開発の進歩は、理想的にはアプリケーションのビジネスロジックのみに限って、アプリケーション自身のコードの量を減らすことを意味します。
ただし、これは無料ではありません-単純なプロジェクトでも依存関係の数が50を超えています(WEB-INF \ libのPetClinicには61個のjarがあります)。
もちろん、それらすべてを知る必要はありません。いくつかの瓶がバックグラウンドで引き上げられており、完成した戦争を見たり、
mvn project-info-reports:dependencies
実行し
mvn project-info-reports:dependencies
(IDEA:依存関係の表示... Mavenプロジェクトで)。 しかし、あなたは主なもので作業する必要があります。 そして戦うために
一部の機能では、数時間、場合によっては数日かかることもあります。 そして、フレームワーク自体のバグに対処する必要があります...
最近、Pet Clinicに触発され、これらのテクノロジーに関するウェビナーを作成したときに、Todo管理リストアプリケーションを作成しました。to-doリスト管理
承認とユーザー登録を行います。 Spring Security / Pet Clinicの依存関係に追加された最新のSpring Security
テストと
jQuery JeditableおよびjQuery通知プラグイン。
この記事のボリュームでは、アプリケーションの作成手順を説明することはできません(アプリケーションの作成に関するウェビナーは30時間かかります)。
したがって、ここでは、リソース、その作成の過程で生じたいくつかの考えや決定を共有します。
PaaS Herokuで デモアプリケーションを見つけることができます(最初に
起動時に長いダウンロードとサーバーエラーが発生する可能性がある場合は、繰り返します)。
応用例
インターネットには、Spring / JPA / MVC / Securityで構築された多くのアプリケーションがあります。 ソートをダウンロードし、最適なソリューションを選択できます。
- リストの最初はペットクリニック自身です。
- 次に、 Spring Rooを使用したHerokuのペットクリニック 。
- Spring Security Test rwinch / spring-security-test-blogの著者から
- アレクセイ・レチコフのプロジェクトmcgray / TODOShare
- sivaprasadreddy / sivalabs-blog-samples-codeサンプルファミリー
- フルゼンシュタイン/ security-spr
- e-ivaldi / easy-bank
- fpants /ショッピングカート
- JetBrainsスレーブ開発者Andrey Cheptsov cheptsov / SpringMVCAppから
- タンポポタンポポのサンプルの例
- SpringExceptionHandling
- spring-security-login-example-database
- 最後にmkyongマニュアル: Springチュートリアル 、 Spring MVCチュートリアル 、 Spring Securityチュートリアル
Spring名前空間の構成
Spring構成では、名前空間の下に実装の詳細を隠す傾向があります。
構成は小さくなり、理解しやすくなりますが、カスタマイズまたはデバッグのプロセスはそれほど簡単ではありません。まず、ビンを見つける必要があります。
どこに実装されていますか。
初期化の例の比較
ベース :
<bean class="org.springframework.jdbc.datasource.init.DataSourceInitializer" depends-on="entityManagerFactory"> <property name="databasePopulator" ref="resourceDatabasePopulator"/> <property name="dataSource" ref="dataSource"/> </bean> <bean id="resourceDatabasePopulator" class="org.springframework.jdbc.datasource.init.ResourceDatabasePopulator"> <property name="scripts"> <array> <value>classpath*:db/${jdbc.initLocation}</value> <value>classpath*:db/populateDB.sql</value> </array> </property> </bean>
そして
<jdbc:initialize-database data-source="dataSource" enabled="${database.init}"> <jdbc:script location="classpath:db/${jdbc.initLocation}"/> <jdbc:script location="classpath:db/populateDB.sql"/> </jdbc:initialize-database>
これは、以前のAcegi SecurityとSpring Securityを比較するときに特に顕著です(すべてのフィルターは名前空間securityの下に隠されています )。
テストの@Transactional
Springのテストでは、トランザクション性を使用するのが一般的です。各テストの実行後、ベースロールバックは元の状態に戻ります。
ただし、@ Transactional自体がテストの動作に強く影響します。たとえば、@ Transactionalサービス/リポジトリを忘れてしまい、テストに合格し、アプリケーションがクラッシュしました。
さらに悪いことに、テストがデータベースからエンティティを取得して比較する場合:
それらは同じトランザクションコンテキストに分類され、テストされたメソッドの動作は多少異なります(セーブの削除またはデタッチのみ)。
テストデバッグ中の基本状態も、テストトランザクションが完了するまで表示されません。
各テストの前にベース初期化子を使用する方がより正直です。
<bean class="DbPopulator"> <constructor-arg name="scriptLocation" value="classpath:db/populateDB.sql"/> </bean>
public class DbPopulator extends ResourceDatabasePopulator { private static final ResourceLoader RESOURCE_LOADER = new DefaultResourceLoader(); @Autowired private DataSource dataSource; public DbPopulator(String scriptLocation) { super(RESOURCE_LOADER.getResource(scriptLocation)); } public void execute() { DatabasePopulatorUtils.execute(this, dataSource); } } @ContextConfiguration("classpath:spring/spring-app.xml") @RunWith(SpringJUnit4ClassRunner.class) @ActiveProfiles({"postgres", "jpa"}) public class TodoItemServiceTest { @Autowired private DbPopulator dbPopulator; @Before public void setUp() throws Exception { dbPopulator.execute(); }
更新:Spring 4.1では、DbPopulatorに代わる注釈が導入されました。
@org.springframework.test.context.jdbc.Sql
EntityManagerFactoryの設定
persistence.xmlで宣言されていないエンティティに関するSpring 3.0のバグに慣れていたので、それがなくてもすべてが機能することに驚きました!
コードを少し掘り下げた後、すべてのターゲット/クラスがエンティティアノテーションについてスキャンされることがわかりました。 また、persistence.xmlを使用せずにJPAを構成できることにも満足しています。
モデルをスキャンするための特定のパッケージを指定し、プロバイダー固有の一般的なJPAパラメーターを構成できます。
そして、それらを共通のdb.propertiesファイルに移動できます:
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean" p:dataSource-ref="dataSource" p:packagesToScan="**.model"> <!--p:persistenceUnitName="persistenceUnit">--> <property name="jpaPropertyMap"> <map> <entry> <key> <util:constant static-field="org.hibernate.cfg.AvailableSettings.FORMAT_SQL"/> </key> <value>${hibernate.format_sql}</value> </entry> <entry> <key> <util:constant static-field="org.hibernate.cfg.AvailableSettings.USE_SQL_COMMENTS"/> </key> <value>${hibernate.use_sql_comments}</value> </entry> </map> </property> <property name="jpaVendorAdapter"> <bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" p:showSql="${jpa.showSql}" p:generateDdl="${jpa.generateDdl}"> </bean> </property> </bean>
接続プールの実装の選択。
DataSource Commons DBCPを実装するという従来の選択は、 地歩を失っているようです。
StackOverflowによると、実装にはプレイフレームワークで使用されるBoneCPを使用する必要があります(既に使用している場合、または使用する場合は、
開発者Plumbrからのレポートで表明されたメモリリークを回避するために、いくつかの努力が必要であることに注意してください。
また、PetClinic はtomcat-jdbcを使用します 。
アプリケーションがTomcatにデプロイされている場合、warに含めることはできません(scope =提供)が、同時に$ TOMCAT_HOME / libに含めることができます
ネイティブのtomcat-jdbcから戦争のライブラリが利用できないため、ベースドライバーを配置する必要があります。
そしてもちろん、Tomcatにデプロイするときは、接続プールを取得する機能を忘れないでください
Tomcat構成context.xmlリソース:
<beans profile="jndi"> <jee:jndi-lookup id="dataSource" jndi-name="java:comp/env/jdbc/javatop"/> </beans>
Spring Data JPA
EntityManagerに基づくメインCRUDの実装でエンティティとキーによってパラメーター化された独自のAbstractDAOを作成するために各プロジェクトに慣れていることは喜ばしいことでしたが、
しかし、彼はついにSpring Data JPAプロジェクトでSpringに参入しました:
JpaRepository<T, ID extends Serializable>
より一般的な
CrudRepository<T, ID extends Serializable>
継承し
CrudRepository<T, ID extends Serializable>
Spring Data Commonsから。
JPAリポジトリを操作することは 、最初は驚くべきことです。
public interface UserRepository extends Repository<User, Integer> { User findByEmail(String email); }
そして、メソッド自体は単一の実装行なしで機能します!
主な情報源へのアピールは、魔法の内部がプロキシ、正規表現、リフレクションであることを示しました。
- まず、
JpaRepositoryFactory.getRepositoryBaseClass
のインターフェースは、実装の1つであるQueryDslJpaRepository
(使用する場合)によってプロキシされます。
Javaの統合クエリ )またはSimpleJpaRepository
- 次に、すべてのメソッドが分析されます-クエリの候補(
DefaultRepositoryInformation.isQueryMethodCandidate
)。
簡略化して、@Query
アノテーションを持つすべてのものと、@Query
ないすべてのものJpaRepository
にJpaRepository
。
- 次に、メソッド名がPartTreeで解析されます
PartTree.PREFIX_TEMPLATE: Pattern.compile("^(find|read|get|count|query)(\\p{Lu}.*?)??By")
財産の本質との通信を求めます。
- 最後に、メソッドはJPA Criteria APIを介して簡単に実装されます 。
読者への修辞的な質問:javaは動的言語と見なすことができます:)?
JpaRepositoryと生成されたメソッドが十分でない場合、独自のメソッドまたはQueryクエリの実装を記述できます 。
@Query
JPQLクエリ(@NamedQueryで生成される)を
@NamedQuery
できます。または、エンティティで既に宣言されている
@NamedQuery
参照できます(何らかの理由で、PetClinic
@NamedQuery
そのような要求は構築段階で構築およびチェックされますが、無視されます)。
たとえば、メソッド
@Modifying @Transactional @Query(name = User.DELETE) int delete(@Param("id") int id);
ユーザー@NamedQueryで宣言された参照
@NamedQueries({ ... @NamedQuery(name = User.DELETE, query = "DELETE FROM User u WHERE u.id=:id") }) public class User extends NamedEntity { public static final String DELETE = "User.delete";
void CrudRepository.delete(ID id)
とは異なり、変更されたレコードの数を返します。
ただし、問題があります
JpaRepository
からビジネスデータアクセスインターフェイスを
JpaRepository
すると、サービスレベルが実装に依存することになります。
また、たとえば、
List<T> findAll(Sort sort)
メソッドでは、
List<T> findAll(Sort sort)
クラスもSpring Dataにあるため、サービスで設定する必要はありません。
インターフェイスメソッドの署名は、
JpaService
署名にバインドされます。 デベースしてログインするのは不便です。 サービスレベルでまったく必要のないすべての
JpaRepository
メソッド、または
org.springframework.data.repository.Repository
トークンから継承する場合、
JpaRepository
検証は行われず
@Override
...
これらの問題はすべて、別のレベルの委任によって解決されます。
public interface ProxyUserRepository extends JpaRepository<User, Integer> { @Modifying @Query("DELETE FROM User u WHERE u.id=?1") @Transactional int delete(int id); @Override @Transactional User save(User user); @Override User findOne(Integer id); @Override List<User> findAll(Sort sort); } @Repository public class DataJpaUserRepository implements UserRepository { private static final Sort SORT_NAME_EMAIL = new Sort("name", "email"); @Autowired private ProxyUserRepository proxy; @Override public boolean delete(int id) { return proxy.delete(id) != 0; } @Override public User save(User user) { return proxy.save(user); } @Override public User get(int id) { return proxy.findOne(id); } @Override public List<User> getAll() { return proxy.findAll(SORT_NAME_EMAIL); } }
最後に:トピックリソース
春
- エフゲニーボリソフ-スプリングリッパー、パート1
- エフゲニーボリソフ-スプリングリッパー、パート2
- Evgeny Borisov-Spring 4.0:新世代
- Alexey Rezchikov:Spring Data-永続性の新しい見方
- 迅速な開発: Spring Roo
メイヴン
- Mavenに関するロシアのリソース。
- プロジェクトの開始とMavenアーキタイプのカスタマイズ
- 古い記事の翻訳Mavenの欠点 。 リストされているもののいくつか
関連性がなくなり、一部は残りました。
- Bintray:Maven Centralへのゲートウェイ
- メイベンボム
[部品表] PetClinicが依存関係を解決するために使用する依存関係。
ロギング
持続性
この記事が気に入ったら、不適切なSpring MVC、Spring Security、Jacksonなどでパート2を準備します。
ご清聴ありがとうございました。取り上げられたトピックについてご意見をお聞かせください。